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

1126 lines
46 KiB
C++
Executable File

/**
* Send AES data to NGS
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Baeuerle, SLSE, 2017-05-08
*/
#include "aes_handler.h"
#include "ngs_handler.h"
#include <Common/participantposition.h>
#include <AreaEffectSimulation/aes_enums.hpp>
#include <AreaEffectSimulation/aes_translation.h>
#include <LtsUtilsCore/dds_bitarray.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <EntityTypeStruct.h>
#include <QTimer>
#include <QDateTime>
using namespace AreaEffectSimulation;
namespace HighLevelArchitecture
{
static MineCorridorModifyRequest *makeMinefieldBreachRequest(const MineCorridor& mc)
{
MineCorridorModifyRequest *req = new MineCorridorModifyRequest;
req->effectDuration(mc.effectDuration());
req->effectStart(mc.effectStart());
req->externalId(mc.externalId());
req->id(mc.id());
req->name(mc.name());
req->participantId(mc.participantId());
req->partyId(mc.partyId());
req->segments(mc.segments());
req->width(mc.width());
return req;
}
static MineAreaModifyRequest *makeMinefieldRequest(const MineArea& ma)
{
if (ma.segments().size() <= 0)
return nullptr;
MineAreaModifyRequest *req = new MineAreaModifyRequest;
req->chargeStruct().chargeTypeId(ma.chargeStruct().chargeTypeId());
req->density(ma.density());
req->distance(0.5);
req->effectDuration(ma.effectDuration());
req->effectMarkingInTa(ma.effectMarkingInTa());
req->effectStart(ma.effectStart());
req->externalId(ma.externalId());
req->id(ma.id());
req->isCenterLine(ma.isCenterLine());
req->isLaidHidden(ma.isLaidHidden());
req->layingProcedureType(ma.layingProcedureType());
req->name(ma.name());
req->participantId(ma.participantId());
req->partyId(ma.partyId());
for (const MineSegment &ms : ma.segments())
req->segments().push_back(ms.positionStart());
const MineSegment &lastSegment = ma.segments().at(ma.segments().size()-1);
req->segments().push_back(Core::GeoPosition2D(lastSegment.positionEnd().lon(), lastSegment.positionEnd().lat()));
req->width(ma.width());
return req;
}
AesHandler::AesHandler(NgsHandler *ngsHandler)
: m_ngsHandler(ngsHandler)
, m_dtcAes(nullptr)
, m_ftcAes(nullptr)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_logger(getLogger("AesHandler"))
{
}
void AesHandler::onMineAreaModifyReply(const Core::FunctionReplyObject &replyObject)
{
if (replyObject.error())
WARNING_LOG(m_logger) << "ModifyReply: " << replyObject();
else
DEBUG_LOG(m_logger) << "ModifyReply: " << replyObject();
m_requestHelper->requestReply(replyObject);
}
int64_t AesHandler::externalId(int aesItemId) const
{
AesItem aesItem;
if (!m_dtcAes->aesItemFromId(aesItemId, aesItem))
return 0;
return aesItem.externalId();
}
bool AesHandler::init()
{
m_dtcAes = Interface::Dtc::create(m_ngsHandler->ddsHandler()->ddsConnector());
m_ftcAes = Interface::Ftc::create(m_ngsHandler->ddsHandler()->ddsConnector());
connect(m_dtcAes.get(), &Interface::Dtc::aesItemViewChanged,
this, &AesHandler::onAesItemViewChanged);
connect(m_dtcAes.get(), &Interface::Dtc::triggeredImpactsChanged,
this, &AesHandler::onTriggeredImpactsChanged);
#ifdef SUPPORT_AES_EFFECTS
connect(m_dtcAes.get(), &Interface::Dtc::effectsChanged,
this, &AesHandler::onEffectsChanged);
#endif // SUPPORT_AES_EFFECTS
connect(m_dtcAes.get(), &Interface::Dtc::explosionSingleChanged,
this, &AesHandler::onAesExplosionSingleChanged);
connect(m_dtcAes.get(), &Interface::Dtc::mineAreaChanged,
this, &AesHandler::onAesMineAreaChanged);
connect(m_dtcAes.get(), &Interface::Dtc::mineCorridorChanged,
this, &AesHandler::onAesMineCorridorChanged);
connect(m_dtcAes.get(), &Interface::Dtc::nContaminationChanged,
this, &AesHandler::onAesNContaminationChanged);
connect(m_dtcAes.get(), &Interface::Dtc::bCContaminationChanged,
this, &AesHandler::onAesBCContaminationChanged);
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesNameChanged,
this, &AesHandler::onAesNameChanged);
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesForceIdentifierChanged,
this, &AesHandler::onAesForceIdentifierChanged);
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesActivationTimeChanged,
this, &AesHandler::onAesActivationTimeChanged);
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesChargeChanged,
this, &AesHandler::onAesChargeChanged);
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesDurationChanged,
this, &AesHandler::onAesDurationChanged);
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesPointsDataChanged,
this, &AesHandler::onAesPointsDataChanged);
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesRemoveItem,
this, &AesHandler::onAesRemoveItem);
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::newMinefield,
this, &AesHandler::onNewMinefield);
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::newMinefieldBreach,
this, &AesHandler::onNewMinefieldBreach);
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::munitionDetonation,
this, &AesHandler::onMunitionDetonation);
#ifdef SUPPORT_EXPLOSION_CLUSTER_SINGLE_EFFECT
connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::munitionDetonationExplosionClusterSingleEffectOnly,
this, &AesHandler::onMunitionDetonationExplosionClusterSingleEffect);
#endif
return m_dtcAes->enableAesItemView() &&
m_dtcAes->enableExplosionSingle() &&
m_dtcAes->enableMineArea() &&
m_dtcAes->enableTriggeredImpacts() &&
#ifdef SUPPORT_EXPLOSION_CLUSTER_SINGLE_EFFECT
m_ftcAes->enableExplosionClusterSingleEffectOnlyModify() &&
#endif
#ifdef SUPPORT_AES_EFFECTS // GUEZE-2570 / EXPLOSION_CLUSTER
m_dtcAes->enableEffects() &&
#endif
m_dtcAes->enableMineCorridor() &&
m_ftcAes->enableMineCorridorModify() &&
m_ftcAes->enableMineCorridorRemove() &&
m_dtcAes->enableNContamination() &&
m_dtcAes->enableBCContamination() &&
m_ftcAes->enableMineAreaRemove() &&
m_ftcAes->enableMineAreaModify() &&
m_ftcAes->enableExplosionSingleModify();
}
void AesHandler::onAesItemViewChanged(const AesItemView &data, DataModification modType)
{
if (m_logger.isDebugEnabled())
{
QStringList formString;
formString.reserve(data.form().size());
for (const auto &pos : data.form())
formString << ParticipantPosition(pos).toString();
DEBUG_LOG(m_logger) << "\n##############################"
<< "\n##### AesItemViewChanged #####"
<< "\n##############################"
<< "\nid: " << data.id()
<< "\nsampleTime: " << data.sampleTime()
<< "\naesTypeId: " << toString(data.aesTypeId())
<< "\naesItemId: " << data.aesItemId()
<< "\nform: " << formString.join(QStringLiteral(", "))
<< "\nboundingBoxBottomLeft: " << ParticipantPosition(data.boundingBoxBottomLeft()).toString()
<< "\nboundingBoxTopRight: " << ParticipantPosition(data.boundingBoxTopRight()).toString()
<< "\neffectStateId: " << toString(data.effectStateId())
<< "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set"))
<< "\nchargeTypeId: " << data.chargeStruct().chargeTypeId()
<< "\neffectStart: " << data.effectStart() << "\n";
}
if (modType == DataModification::eRemoved ||
data.effectStateId() == AesEffectState::EsExpired ||
data.effectStateId() == AesEffectState::EsRemoved)
{
DEBUG_LOG(m_logger) << "Item view with id " << data.aesItemId() << " removed";
m_aesItemViews.remove(data.aesItemId());
m_takenIndicesForAesItem.remove(data.aesItemId());
m_ngsHandler->ngsConnector()->setItemForm(data.aesItemId());
}
// Only care about Explosion Areas for triggered impacts and for storing:
else if (data.effectStateId() == AesEffectState::EsPrepared &&
data.aesTypeId() == AesType_def::AtExplosionAreaSingleExplosions)
{
DEBUG_LOG(m_logger) << "Item view with id " << data.aesItemId() << " added";
m_aesItemViews.insert(data.aesItemId(), data);
m_takenIndicesForAesItem.insert(data.aesItemId(), QVector<int32_t>());
}
// On BCContaminations directly update in NgsConnector:
else if (data.aesTypeId() == AesType_def::AtBCContamination)
{
m_ngsHandler->ngsConnector()->setItemForm(data.aesItemId(), data.aesTypeId().underlying(), data.form());
DEBUG_LOG(m_logger) << "Item view with id " << data.aesItemId() << " directly updated in ngsConnector";
}
}
void AesHandler::onTriggeredImpactsChanged(const TriggeredImpacts &data, DataModification modType)
{
if (m_logger.isDebugEnabled())
{
QString bitfield = QStringLiteral("[ ");
for (uint8_t bit : data.bitfield())
{
bitfield.append(QString::number(bit));
bitfield.append(QStringLiteral(" "));
}
bitfield.append(QStringLiteral("]"));
DEBUG_LOG(m_logger) << "\n#####################################"
<< "\n##### triggered impacts changed #####"
<< "\n#####################################"
<< "\nid: " << data.id()
<< "\naesItemId: " << data.aesItemId()
<< "\naesTypeId: " << toString(data.aesTypeId())
<< "\nbitfield: " << bitfield
<< "\nimpactCount: " << data.impactCount()
<< "\nsampleTime: " << data.sampleTime() << "\n";
}
// Clean up if removed / Don't care if not in before.
if (modType == DataModification::eRemoved)
{
m_aesItemViews.remove(data.aesItemId());
m_takenIndicesForAesItem.remove(data.aesItemId());
return;
}
if (data.aesTypeId() != AesType_def::AtExplosionAreaSingleExplosions)
return;
// If no aesItemView, no takenIndices also. They are in sync.
if (!m_aesItemViews.contains(data.aesItemId()))
return;
const AesItemView &aesItemView = m_aesItemViews[data.aesItemId()];
// Triggered Impacts are either belonging to Explosion Areas or Mine Areas.
int chargeTypeId = m_dtcAes->explosionArea(data.aesItemId()).chargeStruct().chargeTypeId();
if (chargeTypeId <= 0)
return;
rpr2::ForceIdentifierEnum8::ET forceId = aesItemView.partyId().is_set() ? m_ngsHandler->ppmHandler()->forceIdentifierFromPartyId(aesItemView.partyId().get()) : rpr2::ForceIdentifierEnum8::Other;
for (int32_t bitFieldIdx = 0; bitFieldIdx < data.impactCount(); ++bitFieldIdx)
{
// no break, because every bit can be a hit
if (LtsUtils::BitArray::testBit(data.bitfield(), bitFieldIdx) ||
m_takenIndicesForAesItem.value(data.aesItemId()).contains(bitFieldIdx))
continue;
m_takenIndicesForAesItem[data.aesItemId()].append(bitFieldIdx);
ParticipantPosition pos(aesItemView.form()[bitFieldIdx], data.sampleTime());
m_ngsHandler->ngsConnector()->sendMunitionDetonation(pos, chargeTypeId, forceId);
}
}
#ifdef SUPPORT_AES_EFFECTS
void AesHandler::onEffectsChanged(const Effects &data, DataModification modType)
{
// GUEZE-2570 3D Wirksim - Umstellung HLA auf ExplosionCluster
// Part1: DDS -> HLA
const int aesItemId = data.aesItemId();
// Clean up if removed / Don't care if not in before.
if (modType == DataModification::eRemoved)
{
m_handledImpactsStorage.removeAesItem(aesItemId);
return;
}
if (data.aesTypeId() != AesType_def::AtExplosionClusterSingleExplosions)
return;
const std::vector<AreaEffectSimulation::SingleEffect> &singleEffectsRef = data.singleEffects();
if (singleEffectsRef.empty())
return;
// if explosionCluster could not be found, the values is also 0; No extra check needed.
const AreaEffectSimulation::ExplosionCluster &exCluster = m_dtcAes->explosionCluster(aesItemId);
if (exCluster.id() != aesItemId)
return;
// If neither Party nor Participant is set or participant id is smaller than 0, this is an external one that should not be published!
// Fix for [GUEZE-3601] External impacts are being published for a second time by us
if (!exCluster.partyId().is_set() &&
(!exCluster.participantId().is_set() || exCluster.participantId().get() <= 0))
return;
const int chargeTypeId = exCluster.chargeStruct().chargeTypeId();
if (chargeTypeId <= 0)
return;
//
// real work:
//
// partyId to forceId:
const rpr2::ForceIdentifierEnum8::ET forceId = exCluster.partyId().is_set() ? m_ngsHandler->ppmHandler()->forceIdentifierFromPartyId(exCluster.partyId().get()) : rpr2::ForceIdentifierEnum8::Other;
int curSeIndex = -1;
for (const AreaEffectSimulation::SingleEffect &se : qAsConst(singleEffectsRef))
{
++curSeIndex;
// only SesTriggered are relevant:
if (se.singleEffectState() != AreaEffectSimulation::AesSingleEffectState_def::SesTriggered)
continue;
// compare current triggered idx with triggered idx of the past
if (m_handledImpactsStorage.isIndexProcessed(aesItemId, curSeIndex))
continue;
// send to ngsHandler
// ParticipantPosition pos(aesItemView.form()[bitFieldIdx], data.sampleTime());
ParticipantPosition pos(se.position(), se.singleEffectTime());
m_ngsHandler->ngsConnector()->sendMunitionDetonation(pos, chargeTypeId, forceId);
// update storage
m_handledImpactsStorage.setIndexProcessed(aesItemId, curSeIndex);
} // for
}
#endif // SUPPORT_AES_EFFECTS
void AesHandler::onAesExplosionSingleChanged(const ExplosionSingle &data, DataModification modType)
{
Q_UNUSED(modType);
// Maybe this works also...?
// if (data.externalId() > 0)
// return;
DEBUG_LOG(m_logger) << "\n####################################"
<< "\n##### single explosion changed #####"
<< "\n####################################"
<< "\nid: " << data.id()
<< "\nname: " << data.name()
<< "\nisDeleted: " << data.isDeleted()
<< "\nisUsed: " << data.isUsed()
<< "\nsampleTime: " << data.sampleTime()
<< "\nchargeTypeId: " << data.chargeStruct().chargeTypeId()
<< "\neffectDuration: " << data.effectDuration()
<< "\neffectStart: " << (data.effectStart().is_set() ? QString::number(data.effectStart().get()) : QStringLiteral("not set"))
<< "\neffectStateId: " << toString(data.effectStateId())
<< "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set"))
<< "\nparticipantId: " << (data.participantId().is_set() ? QString::number(data.participantId().get()) : QStringLiteral("not set"))
<< "\nimpactPosition: " << ParticipantPosition(data.impactPosition()).toString()
<< "\nfireRequestTime: " << data.fireRequestTime()
<< "\naltitude: " << data.altitude()
<< "\npurpose: " << data.purpose() << "\n";
if (data.effectStateId() != AesEffectState::EsActivated)
return;
// If neither Party nor Participant is set or participant id is smaller than 0, this is an external one that should not be published!
if (!data.partyId().is_set() &&
(!data.participantId().is_set() || data.participantId().get() <= 0))
return;
// If it's active (it's only one second active and not likely to have several updates in the meantime...
ParticipantPosition pos(data.impactPosition(), data.effectStart().is_set() ? data.effectStart().get() : data.sampleTime());
rpr2::ForceIdentifierEnum8::ET forceId = data.partyId().is_set() ? m_ngsHandler->ppmHandler()->forceIdentifierFromPartyId(data.partyId().get()) : rpr2::ForceIdentifierEnum8::Other;
m_ngsHandler->ngsConnector()->sendMunitionDetonation(pos, data.chargeStruct().chargeTypeId(), forceId);
}
void AesHandler::onAesMineAreaChanged(const MineArea &data, DataModification modType)
{
Q_UNUSED(modType);
DEBUG_LOG(m_logger) << "\n#############################"
<< "\n##### mine area changed #####"
<< "\n#############################"
<< "\nid: " << data.id()
<< "\nname: " << data.name()
<< "\nisDeleted: " << data.isDeleted()
<< "\nisUsed: " << data.isUsed()
<< "\nsampleTime: " << data.sampleTime()
<< "\nchargeTypeId: " << data.chargeStruct().chargeTypeId()
<< "\neffectDuration: " << data.effectDuration()
<< "\neffectStart: " << (data.effectStart().is_set() ? QString::number(data.effectStart().get()) : QStringLiteral("not set"))
<< "\neffectStateId: " << toString(data.effectStateId())
<< "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set"))
<< "\nparticipantId: " << (data.participantId().is_set() ? QString::number(data.participantId().get()) : QStringLiteral("not set"))
<< "\n";
m_ngsHandler->ngsConnector()->guezMineField(data);
}
void AesHandler::onAesMineCorridorChanged(const MineCorridor &data, DataModification modType)
{
Q_UNUSED(modType);
DEBUG_LOG(m_logger) << "\n#################################"
<< "\n##### mine corridor changed #####"
<< "\n#################################"
<< "\nid: " << data.id()
<< "\nname: " << data.name()
<< "\nisDeleted: " << data.isDeleted()
<< "\nisUsed: " << data.isUsed()
<< "\nsampleTime: " << data.sampleTime()
<< "\nchargeTypeId: " << data.chargeStruct().chargeTypeId()
<< "\neffectDuration: " << data.effectDuration()
<< "\neffectStart: " << (data.effectStart().is_set() ? QString::number(data.effectStart().get()) : QStringLiteral("not set"))
<< "\neffectStateId: " << toString(data.effectStateId())
<< "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set"))
<< "\nparticipantId: " << (data.participantId().is_set() ? QString::number(data.participantId().get()) : QStringLiteral("not set"))
<< "\n";
m_ngsHandler->ngsConnector()->guezMineFieldBreach(data);
}
void AesHandler::onAesNContaminationChanged(const NContamination &data, DataModification modType)
{
Q_UNUSED(modType);
m_ngsHandler->ngsConnector()->guezNuclearAgent(data);
DEBUG_LOG(m_logger) << "\n####################################"
<< "\n##### n contamination changed #####"
<< "\n####################################"
<< "\nid: " << data.id()
<< "\nname: " << data.name()
<< "\nisDeleted: " << data.isDeleted()
<< "\nisUsed: " << data.isUsed()
<< "\nsampleTime: " << data.sampleTime()
<< "\nchargeTypeId: " << data.chargeStruct().chargeTypeId()
<< "\neffectDuration: " << data.effectDuration()
<< "\neffectStart: " << (data.effectStart().is_set() ? QString::number(data.effectStart().get()) : QStringLiteral("not set"))
<< "\neffectStateId: " << toString(data.effectStateId())
<< "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set"))
<< "\nparticipantId: " << (data.participantId().is_set() ? QString::number(data.participantId().get()) : QStringLiteral("not set"))
<< "\n";
}
void AesHandler::onAesBCContaminationChanged(const BCContamination &data, DataModification modType)
{
Q_UNUSED(modType);
m_ngsHandler->ngsConnector()->guezChemicalAgent(data);
DEBUG_LOG(m_logger) << "\n####################################"
<< "\n##### bc contamination changed #####"
<< "\n####################################"
<< "\nid: " << data.id()
<< "\nname: " << data.name()
<< "\nisDeleted: " << data.isDeleted()
<< "\nisUsed: " << data.isUsed()
<< "\nsampleTime: " << data.sampleTime()
<< "\nchargeTypeId: " << data.chargeStruct().chargeTypeId()
<< "\neffectDuration: " << data.effectDuration()
<< "\neffectStart: " << (data.effectStart().is_set() ? QString::number(data.effectStart().get()) : QStringLiteral("not set"))
<< "\neffectStateId: " << toString(data.effectStateId())
<< "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set"))
<< "\nparticipantId: " << (data.participantId().is_set() ? QString::number(data.participantId().get()) : QStringLiteral("not set"))
<< "\n";
}
bool AesHandler::isModifiable(const AreaEffectSimulation::AesItem &item)
{
return (item.effectStateId() == AesEffectState_def::EsCreated ||
item.effectStateId() == AesEffectState_def::EsPrepared ||
item.effectStateId() == AesEffectState_def::EsUnknown ||
item.effectStateId() == AesEffectState_def::EsReceived);
}
// HLA -> DDS
void AesHandler::onAesNameChanged(qint64 identifierInt, const std::string &newName)
{
// No "isModifiable(item)" used here, as Name is more likely changeable.
int aesItemId = 0;
AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId);
switch (type.underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
break;
case AreaEffectSimulation::AesType_def::AtMineCorridor:
{
MineCorridorModifyRequest *req = static_cast<MineCorridorModifyRequest*>(m_pendingRequests.value(aesItemId));
if (!req)
{
AreaEffectSimulation::MineCorridor item = m_dtcAes->mineCorridor(aesItemId);
if (item.name() == newName)
return;
req = makeMinefieldBreachRequest(item);
addRequestToQueue(aesItemId, req);
}
req->name(newName);
break;
}
case AreaEffectSimulation::AesType_def::AtMineArea:
{
MineAreaModifyRequest *req = static_cast<MineAreaModifyRequest*>(m_pendingRequests.value(aesItemId));
if (!req)
{
AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId);
if (item.name() == newName)
return;
req = makeMinefieldRequest(item);
addRequestToQueue(aesItemId, req);
}
req->name(newName);
break;
}
case AreaEffectSimulation::AesType_def::AtNContamination:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionArea:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtAirSupportImpact:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtUnknown:
case AreaEffectSimulation::AesType_def::AtDangerArea:
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
case AreaEffectSimulation::AesType_def::AtBorderline:
case AreaEffectSimulation::AesType_def::AtTechnicalArea:
case AreaEffectSimulation::AesType_def::AtReconArea:
case AreaEffectSimulation::AesType_def::AtDusSingleMine:
case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions:
case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines:
case AreaEffectSimulation::AesType_def::AtGasPipe:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory:
case AreaEffectSimulation::AesType_def::AtBoobyTrap:
case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary:
case AreaEffectSimulation::AesType_def::AtOffRouteMine:
case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary:
case AreaEffectSimulation::AesType_def::AtExplosionCluster:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory:
case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine:
break;
}
}
void AesHandler::onAesRemoveItem(qint64 identifierInt)
{
int aesItemId = 0;
AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId);
Core::RemoveElementRequest req(aesItemId);
DEBUG_LOG(m_logger) << "Remove Item for " << aesItemId << " requested. Type: " << type;
switch (type.underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
break;
case AreaEffectSimulation::AesType_def::AtMineCorridor:
{
m_requestHelper->startSingleRequest([req, this]()
{
return m_ftcAes->mineCorridorRemoveRequest(req, this);
});
break;
}
case AreaEffectSimulation::AesType_def::AtMineArea:
{
m_requestHelper->startSingleRequest([req, this]()
{
return m_ftcAes->mineAreaRemoveRequest(req, this);
});
break;
}
case AreaEffectSimulation::AesType_def::AtNContamination:
return; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionArea:
return; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
return; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtAirSupportImpact:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtUnknown:
case AreaEffectSimulation::AesType_def::AtDangerArea:
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
case AreaEffectSimulation::AesType_def::AtBorderline:
case AreaEffectSimulation::AesType_def::AtTechnicalArea:
case AreaEffectSimulation::AesType_def::AtReconArea:
case AreaEffectSimulation::AesType_def::AtDusSingleMine:
case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions:
case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines:
case AreaEffectSimulation::AesType_def::AtGasPipe:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory:
case AreaEffectSimulation::AesType_def::AtBoobyTrap:
case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary:
case AreaEffectSimulation::AesType_def::AtOffRouteMine:
case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary:
case AreaEffectSimulation::AesType_def::AtExplosionCluster:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory:
case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine:
return;
}
}
void AesHandler::onAesActivationTimeChanged(qint64 identifierInt, qint64 msecsSinceEpoch)
{
int aesItemId = 0;
AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId);
qint64 earliest = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch() + 5000;
if (msecsSinceEpoch < earliest && msecsSinceEpoch > 0)
msecsSinceEpoch = earliest;
switch (type.underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
break;
case AreaEffectSimulation::AesType_def::AtMineCorridor:
{
MineCorridorModifyRequest *req = static_cast<MineCorridorModifyRequest*>(m_pendingRequests.value(aesItemId));
if (!req)
{
AreaEffectSimulation::MineCorridor item = m_dtcAes->mineCorridor(aesItemId);
if ((item.effectStart().is_set() && item.effectStart().get() == msecsSinceEpoch) || !isModifiable(item))
return;
req = makeMinefieldBreachRequest(item);
addRequestToQueue(aesItemId, req);
}
req->effectStart(msecsSinceEpoch);
break;
}
case AreaEffectSimulation::AesType_def::AtMineArea:
{
DEBUG_LOG(m_logger) << "onAesActivationTimeChanged / MineArea";
MineAreaModifyRequest *req = static_cast<MineAreaModifyRequest*>(m_pendingRequests.value(aesItemId));
if (!req)
{
DEBUG_LOG(m_logger) << "onAesActivationTimeChanged / MineArea - Request NOT found";
AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId);
if ((item.effectStart().is_set() && item.effectStart().get() == msecsSinceEpoch) || !isModifiable(item))
return;
req = makeMinefieldRequest(item);
addRequestToQueue(aesItemId, req);
}
req->effectStart(msecsSinceEpoch);
break;
}
case AreaEffectSimulation::AesType_def::AtNContamination:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionArea:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtAirSupportImpact:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtUnknown:
case AreaEffectSimulation::AesType_def::AtDangerArea:
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
case AreaEffectSimulation::AesType_def::AtBorderline:
case AreaEffectSimulation::AesType_def::AtTechnicalArea:
case AreaEffectSimulation::AesType_def::AtReconArea:
case AreaEffectSimulation::AesType_def::AtDusSingleMine:
case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions:
case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines:
case AreaEffectSimulation::AesType_def::AtGasPipe:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory:
case AreaEffectSimulation::AesType_def::AtBoobyTrap:
case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary:
case AreaEffectSimulation::AesType_def::AtOffRouteMine:
case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary:
case AreaEffectSimulation::AesType_def::AtExplosionCluster:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory:
case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine:
break;
}
}
// HLA -> DDS
void AesHandler::onAesForceIdentifierChanged(qint64 identifierInt, int partyId)
{
int aesItemId = 0;
AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId);
switch (type.underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
break;
case AreaEffectSimulation::AesType_def::AtMineCorridor:
{
MineCorridorModifyRequest *req = static_cast<MineCorridorModifyRequest*>(m_pendingRequests.value(aesItemId));
if (!req)
{
AreaEffectSimulation::MineCorridor item = m_dtcAes->mineCorridor(aesItemId);
if (item.partyId() == partyId || !isModifiable(item))
return;
req = makeMinefieldBreachRequest(item);
addRequestToQueue(aesItemId, req);
}
req->partyId(partyId);
break;
}
case AreaEffectSimulation::AesType_def::AtMineArea:
{
MineAreaModifyRequest *req = static_cast<MineAreaModifyRequest*>(m_pendingRequests.value(aesItemId));
if (!req)
{
AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId);
if (item.partyId() == partyId || !isModifiable(item))
return;
req = makeMinefieldRequest(item);
addRequestToQueue(aesItemId, req);
}
req->partyId(partyId);
break;
}
case AreaEffectSimulation::AesType_def::AtNContamination:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionArea:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtAirSupportImpact:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtUnknown:
case AreaEffectSimulation::AesType_def::AtDangerArea:
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
case AreaEffectSimulation::AesType_def::AtBorderline:
case AreaEffectSimulation::AesType_def::AtTechnicalArea:
case AreaEffectSimulation::AesType_def::AtReconArea:
case AreaEffectSimulation::AesType_def::AtDusSingleMine:
case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions:
case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines:
case AreaEffectSimulation::AesType_def::AtGasPipe:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory:
case AreaEffectSimulation::AesType_def::AtBoobyTrap:
case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary:
case AreaEffectSimulation::AesType_def::AtOffRouteMine:
case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary:
case AreaEffectSimulation::AesType_def::AtExplosionCluster:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory:
case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine:
break;
}
}
static inline int checkDuration(quint32 u_time, quint32 div, NGL::INGLLogger &logger)
{
const auto maxDuration = std::numeric_limits<int>::max() / div;
if (u_time > maxDuration)
{
WARNING_LOG(logger) << "Got an effect duration which is too long for us - limiting to "
<< maxDuration << "msec";
u_time = maxDuration;
Q_ASSERT(false);
}
const int timeMSec = static_cast<int>(u_time);
return timeMSec;
}
void AesHandler::onAesDurationChanged(qint64 identifierInt, quint32 u_time)
{
int aesItemId = 0;
AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId);
switch (type.underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
break;
case AreaEffectSimulation::AesType_def::AtMineCorridor:
{
MineCorridorModifyRequest *req = static_cast<MineCorridorModifyRequest*>(m_pendingRequests.value(aesItemId));
const int timeMSec = checkDuration(u_time, 60 * 60 * 1000, m_logger); // Hours
if (!req)
{
AreaEffectSimulation::MineCorridor item = m_dtcAes->mineCorridor(aesItemId);
if (item.effectDuration() == timeMSec || !isModifiable(item))
return;
req = makeMinefieldBreachRequest(item);
addRequestToQueue(aesItemId, req);
}
req->effectDuration(timeMSec);
break;
}
case AreaEffectSimulation::AesType_def::AtMineArea:
{
MineAreaModifyRequest *req = static_cast<MineAreaModifyRequest*>(m_pendingRequests.value(aesItemId));
const int timeMSec = checkDuration(u_time, 60 * 60 * 1000, m_logger); // Hours
if (!req)
{
AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId);
if (item.effectDuration() == timeMSec || !isModifiable(item))
return;
req = makeMinefieldRequest(item);
addRequestToQueue(aesItemId, req);
}
req->effectDuration(timeMSec);
break;
}
case AreaEffectSimulation::AesType_def::AtNContamination:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionArea:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtAirSupportImpact:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtUnknown:
case AreaEffectSimulation::AesType_def::AtDangerArea:
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
case AreaEffectSimulation::AesType_def::AtBorderline:
case AreaEffectSimulation::AesType_def::AtTechnicalArea:
case AreaEffectSimulation::AesType_def::AtReconArea:
case AreaEffectSimulation::AesType_def::AtDusSingleMine:
case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions:
case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines:
case AreaEffectSimulation::AesType_def::AtGasPipe:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory:
case AreaEffectSimulation::AesType_def::AtBoobyTrap:
case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary:
case AreaEffectSimulation::AesType_def::AtOffRouteMine:
case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary:
case AreaEffectSimulation::AesType_def::AtExplosionCluster:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory:
case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine:
break;
}
}
void AesHandler::onAesChargeChanged(qint64 identifierInt, int chargeTypeId)
{
int aesItemId = 0;
AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId);
switch (type.underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
break;
case AreaEffectSimulation::AesType_def::AtMineCorridor:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtMineArea:
{
MineAreaModifyRequest *req = static_cast<MineAreaModifyRequest*>(m_pendingRequests.value(aesItemId));
if (!req)
{
AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId);
if (item.chargeStruct().chargeTypeId() == chargeTypeId && !isModifiable(item))
return;
req = makeMinefieldRequest(item);
addRequestToQueue(aesItemId, req);
}
req->chargeStruct().chargeTypeId(chargeTypeId);
break;
}
case AreaEffectSimulation::AesType_def::AtNContamination:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionArea:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtAirSupportImpact:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtUnknown:
case AreaEffectSimulation::AesType_def::AtDangerArea:
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
case AreaEffectSimulation::AesType_def::AtBorderline:
case AreaEffectSimulation::AesType_def::AtTechnicalArea:
case AreaEffectSimulation::AesType_def::AtReconArea:
case AreaEffectSimulation::AesType_def::AtDusSingleMine:
case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions:
case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines:
case AreaEffectSimulation::AesType_def::AtGasPipe:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory:
case AreaEffectSimulation::AesType_def::AtBoobyTrap:
case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary:
case AreaEffectSimulation::AesType_def::AtOffRouteMine:
case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary:
case AreaEffectSimulation::AesType_def::AtExplosionCluster:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory:
case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine:
break;
}
}
bool getCorridorSegment(const std::vector<Core::GeoPosition2D> &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;
}
void AesHandler::onAesPointsDataChanged(qint64 identifierInt, const std::vector<Core::GeoPosition2D> &pos)
{
int aesItemId = 0;
AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId);
DEBUG_LOG(m_logger) << "Points Data changed for Aes Item ID: " << aesItemId << ". Type: " << type;
switch (type.underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
break;
case AreaEffectSimulation::AesType_def::AtMineCorridor:
{
MineCorridorModifyRequest *req = static_cast<MineCorridorModifyRequest*>(m_pendingRequests.value(aesItemId));
if (!req)
{
AreaEffectSimulation::MineCorridor item = m_dtcAes->mineCorridor(aesItemId);
if (!isModifiable(item))
return;
req = makeMinefieldBreachRequest(item);
addRequestToQueue(aesItemId, req);
}
double width;
std::vector<Core::GeoPosition2D> segments;
if (!getCorridorSegment(pos, segments, width))
{
ERROR_LOG(m_logger) << "Could not calculate Mine Area from given Points Data!";
return;
}
req->segments(segments);
req->width(width);
break;
}
case AreaEffectSimulation::AesType_def::AtMineArea:
{
MineAreaModifyRequest *req = static_cast<MineAreaModifyRequest*>(m_pendingRequests.value(aesItemId));
if (!req)
{
AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId);
if (!isModifiable(item))
return;
req = makeMinefieldRequest(item);
addRequestToQueue(aesItemId, req);
}
double width;
std::vector<Core::GeoPosition2D> segments;
if (!getCorridorSegment(pos, segments, width))
{
ERROR_LOG(m_logger) << "Could not calculate Mine Area from given Points Data!";
return;
}
req->segments(segments);
req->isCenterLine(true);
req->width(width);
break;
}
case AreaEffectSimulation::AesType_def::AtNContamination:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionArea:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtAirSupportImpact:
break; // Maybe handled later
case AreaEffectSimulation::AesType_def::AtUnknown:
case AreaEffectSimulation::AesType_def::AtDangerArea:
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
case AreaEffectSimulation::AesType_def::AtBorderline:
case AreaEffectSimulation::AesType_def::AtTechnicalArea:
case AreaEffectSimulation::AesType_def::AtReconArea:
case AreaEffectSimulation::AesType_def::AtDusSingleMine:
case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions:
case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines:
case AreaEffectSimulation::AesType_def::AtGasPipe:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral:
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory:
case AreaEffectSimulation::AesType_def::AtBoobyTrap:
case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary:
case AreaEffectSimulation::AesType_def::AtOffRouteMine:
case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary:
case AreaEffectSimulation::AesType_def::AtExplosionCluster:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions:
case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory:
case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine:
break;
}
}
bool AesHandler::onNewMinefield(const MineAreaModifyRequest &ma)
{
if (!ma.externalId())
return false;
return m_requestHelper->startSingleRequest([this, ma]()
{
return m_ftcAes->mineAreaModifyRequest(ma, this);
});
}
template <>
void AesHandler::onSendRequest(const MineAreaModifyRequest &item)
{
onNewMinefield(item);
}
bool AesHandler::onNewMinefieldBreach(const MineCorridorModifyRequest &mc)
{
if (!mc.externalId().is_set())
return false;
return m_requestHelper->startSingleRequest([this, mc]()
{
return m_ftcAes->mineCorridorModifyRequest(mc, this);
});
}
template <>
void AesHandler::onSendRequest(const MineCorridorModifyRequest &item)
{
onNewMinefieldBreach(item);
}
void AesHandler::onMunitionDetonation(const ExplosionSingleModifyRequest &es)
{
if (!es.externalId().is_set())
return;
m_requestHelper->startSingleRequest([this, es]()
{
return m_ftcAes->explosionSingleModifyRequest(es, this);
});
}
#ifdef SUPPORT_EXPLOSION_CLUSTER_SINGLE_EFFECT
void AesHandler::onMunitionDetonationExplosionClusterSingleEffect(const ExplosionClusterSingleEffectOnlyRequest &es)
{
if (!es.externalId().is_set())
return;
m_requestHelper->startSingleRequest([this, es]()
{
return m_ftcAes->explosionClusterSingleEffectOnlyModifyRequest(es, this);
});
}
#endif // SUPPORT_EXPLOSION_CLUSTER_SINGLE_EFFECT
template <>
void AesHandler::onSendRequest(const ExplosionSingleModifyRequest &item)
{
onMunitionDetonation(item);
}
template <typename T>
void AesHandler::addRequestToQueue(int aesItemId, T *request)
{
m_pendingRequests.insert(aesItemId, request);
QTimer::singleShot(100, this, [this, request, aesItemId]()
{
onSendRequest(*request);
m_pendingRequests.take(aesItemId);
delete request;
});
}
} // namespace HighLevelArchitecture