1142 lines
40 KiB
C++
Executable File
1142 lines
40 KiB
C++
Executable File
/**
|
|
* The Participant class is the base class for either Buildings or ExerciseParticipants.
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Hannes Baeuerle, SLSE, 2016-05-23
|
|
*/
|
|
|
|
|
|
#include "participant.h"
|
|
#include "participant_handler.h"
|
|
#include "unit_position_calculator.h"
|
|
|
|
#include <ParticipantManagement/web_socket_handler.h>
|
|
|
|
#include <QSet>
|
|
|
|
namespace ParticipantManagement
|
|
{
|
|
namespace ParticipantHandling
|
|
{
|
|
|
|
//
|
|
// Participant
|
|
//
|
|
Participant::Participant(ParticipantHandler *participantHandler,
|
|
UnitPositionCalculator *unitPosCalculator,
|
|
const Database::PpmParticipant &data,
|
|
const char *loggerName)
|
|
: m_participantHandler(participantHandler)
|
|
, m_unitPosCalculator(unitPosCalculator)
|
|
, m_lastGearUsage(0)
|
|
, m_lastManipulationReset(0)
|
|
, m_lastNbcState(0)
|
|
, m_lastSpecialSensorData(0)
|
|
, m_participantData(toDdsParticipant(data))
|
|
, m_bPublishPosition(!participantHandler->isUnitType(data.typeId))
|
|
, m_logger(getLogger(loggerName))
|
|
{
|
|
m_participantData.sampleTime(0);
|
|
m_dynamicData.sampleTime(0);
|
|
m_dynamicData.participantId(m_participantData.id());
|
|
|
|
m_participantHandler->setEquipmentNumberForParticipant(0, equipmentNumber(), id());
|
|
m_unitPosCalculator->onSuperiorChanged(id(), superiorId());
|
|
}
|
|
|
|
Participant::~Participant()
|
|
{
|
|
m_unitPosCalculator->onParticipantDeleted(id());
|
|
}
|
|
|
|
void Participant::removeFromDds()
|
|
{
|
|
auto d = dts();
|
|
#ifdef LTS_DEBUG
|
|
// module test creates participants in ex0
|
|
if (d->isParticipantGearEventEnabled())
|
|
#endif
|
|
{
|
|
d->removeParticipantGearEventByKey(id());
|
|
d->removeDynamicParticipantDataByKey(id());
|
|
d->removeParticipantPositionByKey(id());
|
|
d->removeParticipantByKey(id());
|
|
}
|
|
}
|
|
|
|
void Participant::markAsDeleted()
|
|
{
|
|
m_participantData.isDeleted(true);
|
|
m_participantData.superiorId(0);
|
|
m_participantData.inferiorIds().clear();
|
|
m_participantData.hierarchyNumber(0);
|
|
|
|
m_unitPosCalculator->onParticipantDeleted(id());
|
|
}
|
|
|
|
bool Participant::isValidPosition(qint64 sampleTime, const Core::GeoPosition &pos, Core::PositionReportingSource repSource) const
|
|
{
|
|
if (sampleTime < m_positionToPublish.sampleTime())
|
|
return false;
|
|
|
|
// an operator can set an invalid position (so the participant is not displayed on the map)
|
|
if (repSource == Core::PositionReportingSource_def::SetByOperator)
|
|
return true;
|
|
|
|
if (std::isnan(pos.lon()) ||
|
|
std::isnan(pos.lat()))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Participant::setPosition(const TrainingAreaBase::EquipmentPosition &newPosition)
|
|
{
|
|
if (!isValidPosition(newPosition.sampleTime(), newPosition.position().position(), newPosition.position().reportingSource()))
|
|
return false;
|
|
|
|
m_unitPosCalculator->onPositionChanged(id(), newPosition.sampleTime(), newPosition.position().position());
|
|
|
|
m_mutex.lock();
|
|
m_positionToPublish.reportingSource(newPosition.position().reportingSource());
|
|
m_positionToPublish.pos(newPosition.position().position());
|
|
m_positionToPublish.buildingId(newPosition.position().moutObjectId().is_set() ? newPosition.position().moutObjectId().get() : 0);
|
|
m_positionToPublish.roomId(newPosition.position().moutRoomId().is_set() ? newPosition.position().moutRoomId().get() : 0);
|
|
m_positionToPublish.sampleTime(newPosition.sampleTime());
|
|
m_positionToPublish.mountedOn().reset();
|
|
m_mutex.unlock();
|
|
|
|
// When a participant can have mounted participants, then there is always mountedParticipants set, can be empty
|
|
if (newPosition.mountedParticipants().is_set())
|
|
{
|
|
// list of new mounted participants
|
|
std::vector<int32_t> newMountedParticipantIds;
|
|
// list of already mounted participants
|
|
std::vector<int32_t> currentMountedParticipantIds;
|
|
if (m_positionPublished.mountedParticipants().is_set())
|
|
currentMountedParticipantIds = m_positionPublished.mountedParticipants().get();
|
|
|
|
// set new position for all mounted participants
|
|
for (const auto mountedEqId : newPosition.mountedParticipants().get())
|
|
{
|
|
Participant *mountedParticipant = particpantHandler()->participantByEquipmentNumber(mountedEqId);
|
|
|
|
if (!mountedParticipant)
|
|
{
|
|
WARNING_LOG(m_logger) << "Mounted Participant with equipNo " << mountedEqId << " not found - ignoring";
|
|
continue;
|
|
}
|
|
|
|
if (!mountedParticipant->setPosition(newPosition, id()))
|
|
continue;
|
|
mountedParticipant->publishPosition();
|
|
|
|
newMountedParticipantIds.push_back(mountedParticipant->id());
|
|
INFO_LOG(m_logger) << "Mounting Participant with id: " << mountedParticipant->id() << " to id: " << id();
|
|
}
|
|
|
|
// unmount current mounted participants that are not in the list anymore
|
|
for (const auto curMountedParticipantId : currentMountedParticipantIds)
|
|
{
|
|
size_t idx2 = 0;
|
|
while (idx2 < newMountedParticipantIds.size())
|
|
{
|
|
if (curMountedParticipantId == newMountedParticipantIds.at(idx2))
|
|
break;
|
|
++idx2;
|
|
}
|
|
// participant not in newMountedParticipantIds -> unmount
|
|
if (idx2 == newMountedParticipantIds.size())
|
|
unmountParticipantById(newPosition, curMountedParticipantId);
|
|
}
|
|
m_mutex.lock();
|
|
if (newMountedParticipantIds.size() == 0)
|
|
m_positionToPublish.mountedParticipants().reset();
|
|
else
|
|
m_positionToPublish.mountedParticipants(newMountedParticipantIds);
|
|
m_mutex.unlock();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Participant::setPosition(const ParticipantPosition &newPosition, bool bForce)
|
|
{
|
|
if (!bForce && !isValidPosition(newPosition.sampleTime(), newPosition.pos(), newPosition.reportingSource()))
|
|
{
|
|
WARNING_LOG(m_logger) << "position for participant " << m_participantData.id()
|
|
<< " is outdated: " << newPosition
|
|
<< " , cur pos sample time: " << m_positionPublished.sampleTime();
|
|
return false;
|
|
}
|
|
m_unitPosCalculator->onPositionChanged(id(), newPosition.sampleTime(), newPosition.pos());
|
|
m_mutex.lock();
|
|
m_positionToPublish = newPosition;
|
|
m_mutex.unlock();
|
|
return true;
|
|
}
|
|
|
|
bool Participant::setCalculatedPosition(const Core::GeoPosition &pos, int64_t positionTime)
|
|
{
|
|
const bool bNewer = m_positionToPublish.sampleTime() < positionTime;
|
|
m_positionToPublish.pos(pos);
|
|
m_positionToPublish.sampleTime(positionTime);
|
|
return bNewer;
|
|
}
|
|
|
|
bool Participant::setPosition(const TrainingAreaBase::EquipmentPosition &newPosition, int mountedToId)
|
|
{
|
|
if (mountedToId == id())
|
|
{
|
|
WARNING_LOG(m_logger) << "Trying to mount to ourself: " << id();
|
|
return false;
|
|
}
|
|
TrainingAreaBase::EquipmentPosition mountedPosition = newPosition;
|
|
mountedPosition.mountedParticipants().reset();
|
|
|
|
// set position if (new mounted position) or (unmounting and participant is still mounted)
|
|
if ((mountedToId > 0) ||
|
|
(mountedToId <= 0 && m_positionPublished.mountedOn().is_set()))
|
|
setPosition(mountedPosition);
|
|
|
|
m_positionToPublish.reportingSource(newPosition.position().reportingSource());
|
|
if (mountedToId > 0)
|
|
m_positionToPublish.mountedOn(dds::core::optional<int32_t>(mountedToId));
|
|
|
|
return true;
|
|
}
|
|
|
|
void Participant::unmountParticipantById(const TrainingAreaBase::EquipmentPosition &newPosition, int32_t id)
|
|
{
|
|
// no need for a lock as we double_lock ourself when calling unmountParticipantsById out of setPosition
|
|
// the real lock is done in unmountedParticipant->setPosition
|
|
Participant *unmountedParticipant = particpantHandler()->participantById(id);
|
|
unmountedParticipant->setPosition(newPosition, 0);
|
|
unmountedParticipant->publishPosition();
|
|
INFO_LOG(m_logger) << "Unmounting Participant with ID: " << unmountedParticipant->id() << "from ID: " << this->id();
|
|
|
|
}
|
|
|
|
bool Participant::setState(const TrainingAreaBase::EquipmentState &newState, int originatorId)
|
|
{
|
|
auto &stateHistory = m_dynamicData.stateHistory();
|
|
|
|
// search for CombatReady state, ignore newState if it is older
|
|
for (const auto &s : stateHistory)
|
|
{
|
|
if (s.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::inner_enum::CombatReady &&
|
|
s.stateTime() > newState.sampleTime())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::bitset<sizeof(newState.vulnerabilityBits()) * 8> bits(newState.vulnerabilityBits());
|
|
bits.set(static_cast<int>(newState.vulnerabilityState().underlying()));
|
|
|
|
QStringList bitsList;
|
|
for (int i = (int)ProjectDataManagement::VulnerabilityState::inner_enum::CatastrophicKill; i > 0; --i)
|
|
{
|
|
if (bits.test(i))
|
|
bitsList += QString::number(i);
|
|
}
|
|
|
|
bool vulnIgnored = true;
|
|
// find current main state
|
|
ProjectDataManagement::VulnerabilityState mainVulState = newState.vulnerabilityState();
|
|
if (newState.vulnerabilityState() != ProjectDataManagement::VulnerabilityState::TemporarySeverance &&
|
|
newState.vulnerabilityState() != ProjectDataManagement::VulnerabilityState::NearMiss &&
|
|
newState.vulnerabilityState() != ProjectDataManagement::VulnerabilityState::HitWithNoEffect)
|
|
{
|
|
vulnIgnored = false;
|
|
|
|
// only change main vuln state to highest from vulnerabilityBits if a bit smaller than CK (VBG8) is set:
|
|
/* NOTE: 'i > 0' is intended. This ignores vuln CR (VBG0). That's because CR is a special case where
|
|
* the history is resetted, etc. Fortunately the TNE never sends a BC (VBG12) if the last vuln is CR,
|
|
* but sends a CR instead. */
|
|
for (int i = (int)ProjectDataManagement::VulnerabilityState::inner_enum::CatastrophicKill; i > 0; --i)
|
|
{
|
|
if (bits.test(i))
|
|
{
|
|
mainVulState = static_cast<ProjectDataManagement::VulnerabilityState_def::type>(i);
|
|
//WARNING_LOG(m_logger) << "mainVulState was manipulated into: " << i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if mainVulnState *still* is BC (VBG12), something went wrong on the sender side (TNE?)
|
|
if (mainVulState == ProjectDataManagement::VulnerabilityState::VulnerabilityBitsChanged)
|
|
WARNING_LOG(m_logger) << "Sending a BC (VBG12) if the last vuln is CR (VBG0) is not allowed! Something went wrong on the sender side (TNE?)";
|
|
|
|
DEBUG_LOG(m_logger) << "setState for eqid: " << newState.equipmentNumber()
|
|
<< "\nvuln was: " << (int)newState.vulnerabilityState().underlying()
|
|
<< "\nvuln now: " << (int)mainVulState.underlying()
|
|
<< "\nbits (DEC): " << newState.vulnerabilityBits()
|
|
<< "\nbits: " << (bitsList.isEmpty() ? QStringLiteral("<empty>") : bitsList.join(QStringLiteral(",")))
|
|
<< "\nvuln ignored? " << vulnIgnored
|
|
;
|
|
|
|
// some old system or ddsview/LogView sent us an equipmentState with no vulnerability bits -> set at least the current one
|
|
auto vulnerabilityBits = newState.vulnerabilityBits();
|
|
if (vulnerabilityBits == 0)
|
|
{
|
|
const int idx = static_cast<int>(mainVulState.underlying());
|
|
vulnerabilityBits = (1 << idx);
|
|
WARNING_LOG(m_logger) << "Missing vulnerabilityBits! bailing by supplementing by adding this vuln state to the bits";
|
|
}
|
|
|
|
// check if it is a (younger) CombatReady state - remove older
|
|
if (mainVulState == ProjectDataManagement::VulnerabilityState::inner_enum::CombatReady)
|
|
{
|
|
std::vector<ParticipantManagement::StateInformation> currentStates;
|
|
for (const auto &s : stateHistory)
|
|
{
|
|
if (s.stateTime() > newState.sampleTime())
|
|
currentStates.push_back(s);
|
|
}
|
|
m_mutex.lock();
|
|
std::swap(stateHistory, currentStates);
|
|
m_mutex.unlock();
|
|
}
|
|
auto sanResult = SanitationResult::Unhandled;
|
|
auto sanEvaluation = SanitationEvaluation::NotApplicable;
|
|
#ifdef GUEZ_MODE
|
|
if(newState.originatorType() == ProjectDataManagement::StateChangeOriginator::MedicalTimeout)
|
|
{
|
|
/*!
|
|
* \brief originatorId
|
|
* \details For Sanitation Telegram the Split is done in PrtCnv
|
|
* First 2 Bit represent SanitationEvaluation(Versorgungsbewertung)
|
|
* The other 6 Bit represent SanitationResult(Versorgungsauswirkung)
|
|
* For more precise info: ICD52
|
|
*/
|
|
// Only watch lower byte!
|
|
quint8 originatorId = newState.originatorId();
|
|
// If Player Unit has wrong Software, it sends its own equipment number. If so, just take the following values:
|
|
|
|
if (newState.originatorId() > 255)
|
|
{
|
|
|
|
WARNING_LOG(m_logger) << "Participant with EqNo "
|
|
<< m_participantData.equipmentNumber()
|
|
<< " sent wrong Enum Values (Sanitation Eval / ~ Result): "
|
|
<< newState.originatorId()
|
|
<< ". Defaulting to Eval = Okay, Result = Unhandled.";
|
|
originatorId = 1; // Evaluation = Okay, Result = Unhandled.
|
|
}
|
|
quint8 sanEvaluationVal = ((originatorId & 0xc0) >> 6);
|
|
quint8 sanResultVal = (originatorId & 0x3f);
|
|
|
|
if (sanEvaluationVal > 2) // Todo: Check against valid enum values in a better way!
|
|
{
|
|
WARNING_LOG(m_logger) << "Cannot cast upper 2 Bits to SanEvaluation! Defaulting to Okay";
|
|
sanEvaluationVal = 0;
|
|
}
|
|
if (sanResultVal > 4) // Todo: Check against valid enum values in a better way!
|
|
{
|
|
WARNING_LOG(m_logger) << "Cannot cast lower 6 Bits to SanResult! Defaulting to Unhandled";
|
|
sanResultVal = 1;
|
|
}
|
|
sanEvaluation = static_cast<SanitationEvaluation::inner_enum>(sanEvaluationVal);
|
|
sanResult = static_cast<SanitationResult::inner_enum>(sanResultVal);
|
|
}
|
|
#endif
|
|
|
|
//new state Temp Vis Damage
|
|
if(newState.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::VisibleWeaponSystemDamage ||
|
|
newState.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::NearMiss ||
|
|
newState.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::HitWithNoEffect)
|
|
{
|
|
//Get last state in history and use that result
|
|
const ParticipantManagement::StateInformation lastState = ParticipantManagement::youngestStateInformation(stateHistory, false, false); //Don't Skip Sanitation!
|
|
sanResult = lastState.sanitationResult().underlying();
|
|
sanEvaluation = lastState.sanitationEvaluation().underlying();
|
|
}
|
|
|
|
|
|
if(mainVulState == ProjectDataManagement::VulnerabilityState::CombatReady ||
|
|
newState.originatorType() == ProjectDataManagement::StateChangeOriginator::FunctionalArea)
|
|
sanResult = SanitationResult::NoEffect;
|
|
|
|
// [GUEZE-3313] Kontaminierter Teilnehmer trotz Dekontamination weiterhin nicht Vitalität von 100%
|
|
// ICD 52 Kapitel 3.3.2.6.72 VBA / Vitalitaet / Anzeigeindex
|
|
int32_t vitality = newState.vitality();
|
|
|
|
if(mainVulState == ProjectDataManagement::VulnerabilityState::CombatReady)
|
|
vitality = 100;
|
|
|
|
ParticipantManagement::StateInformation state(mainVulState,
|
|
vulnerabilityBits,
|
|
newState.vulnerabilityKindId(),
|
|
originatorId,
|
|
newState.originatorType(),
|
|
newState.originatorChargeTypeId(),
|
|
newState.sampleTime(),
|
|
vitality,
|
|
0,
|
|
sanResult,
|
|
sanEvaluation);
|
|
|
|
for (const ParticipantManagement::StateInformation &hist : stateHistory)
|
|
{
|
|
if (state == hist)
|
|
return false;
|
|
}
|
|
|
|
m_mutex.lock();
|
|
stateHistory.push_back(std::move(state));
|
|
m_mutex.unlock();
|
|
|
|
if (stateHistory.size() == 1)
|
|
m_lastSanMatUsage = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Participant::setSpecialSensorData(const TrainingAreaBase::SpecialSensorData &data)
|
|
{
|
|
if (m_lastSpecialSensorData > data.sampleTime())
|
|
return false;
|
|
m_mutex.lock();
|
|
m_lastSpecialSensorData = data.sampleTime();
|
|
m_dynamicData.specialSensorDataState(data.operationalState());
|
|
m_mutex.unlock();
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Participant::setGear(const TrainingAreaBase::EquipmentGearAssignment &gearAssignment)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Gear Assignment";
|
|
// outdated?
|
|
if (m_lastGearUsage > gearAssignment.sampleTime())
|
|
return false;
|
|
m_lastGearUsage = gearAssignment.sampleTime();
|
|
|
|
// remember the old gears and readd the charges if the gear is still there in the new gear assignment
|
|
auto &gearVec = m_dynamicData.gear();
|
|
std::vector<GearInformation> oldGearData;
|
|
std::swap(gearVec, oldGearData);
|
|
gearVec.reserve(gearAssignment.gears().size());
|
|
QSet<int> newGearIds;
|
|
newGearIds.reserve(gearAssignment.gears().size());
|
|
|
|
for (const TrainingAreaBase::Gear &gear : gearAssignment.gears())
|
|
{
|
|
if (gear.gearId() == 0)
|
|
{
|
|
WARNING_LOG(m_logger) << "Got a gear assignment but gear id is 0 - old Saab AGDUS? - ignoring";
|
|
continue;
|
|
}
|
|
newGearIds += gear.gearId();
|
|
gearVec.emplace_back(gear.gearId(),
|
|
gear.gearTypeId(),
|
|
-1,
|
|
-1,
|
|
gearAssignment.sampleTime(),
|
|
gear.chargeCounting());
|
|
}
|
|
auto it = m_dynamicData.designations().begin();
|
|
while (it != m_dynamicData.designations().end())
|
|
{
|
|
if (newGearIds.contains(it->gearId()))
|
|
++it;
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "Gear Assignment: Removing Designation with gearId: " << it->gearId();
|
|
it = m_dynamicData.designations().erase(it);
|
|
}
|
|
}
|
|
|
|
// readd old charges if gear is still there
|
|
for (GearInformation &gi : oldGearData)
|
|
{
|
|
if (!newGearIds.contains(gi.gearId()))
|
|
continue;
|
|
// to not be ignored
|
|
gi.lastUpdate(gearAssignment.sampleTime());
|
|
setGearCharge(gi);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Participant::setSanitationMaterial(int materialCount, const std::vector<int> &materialStock, int abgSn, qint64 sampleTime, Qualification qualif, qint64 eqNo)
|
|
{
|
|
// outdated?
|
|
if (m_lastSanMatUsage > sampleTime)
|
|
return false;
|
|
m_mutex.lock();
|
|
m_lastSanMatUsage = sampleTime;
|
|
std::vector<SanitationMaterial> newStock;
|
|
newStock.reserve(materialCount);
|
|
|
|
for (int i = 0 ; i < materialCount; i++)
|
|
{
|
|
newStock.emplace_back(i + 1, materialStock.at(i));
|
|
}
|
|
//as we don't change the amount during an exercise we can override directly
|
|
m_dynamicData.sanitationMaterialStock(newStock);
|
|
m_dynamicData.sanitationUniqueId(abgSn);
|
|
m_dynamicData.qualification(qualif);
|
|
m_dynamicData.sanitationOriginatorEquipNo(eqNo);
|
|
m_mutex.unlock();
|
|
return true;
|
|
}
|
|
|
|
bool Participant::setSanitation(qint64 sanitationProceduresTaken, TrainingAreaBase::SanitationResult sanitationResult, TrainingAreaBase::SanitationEvaluation sanitationEvaluation, int originatorId, TrainingAreaBase::Qualification qualification, qint64 sampleTime)
|
|
{
|
|
auto &stateHistory = m_dynamicData.stateHistory();
|
|
ParticipantManagement::StateInformation lastState;
|
|
|
|
// search for CombatReady state, ignore newState if it is older
|
|
for (const auto &s : stateHistory)
|
|
{
|
|
if (s.stateTime() > lastState.stateTime())
|
|
lastState = s;
|
|
}
|
|
|
|
if (sanitationResult == TrainingAreaBase::SanitationResult::NoEffect && sanitationProceduresTaken == 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
ParticipantManagement::StateInformation state;
|
|
state.originatorId(originatorId);
|
|
state.originatorChargeTypeId(qualification.underlying());
|
|
state.originatorType(ProjectDataManagement::StateChangeOriginator::Sanitation);
|
|
state.vitality(lastState.vitality());
|
|
state.vulnerabilityBits(lastState.vulnerabilityBits());
|
|
state.vulnerabilityKindId(lastState.vulnerabilityKindId());
|
|
state.vulnerabilityState(lastState.vulnerabilityState());
|
|
state.sanitationProceduresTaken(sanitationProceduresTaken);
|
|
state.sanitationResult(static_cast<ParticipantManagement::SanitationResult::inner_enum>(sanitationResult.underlying()));
|
|
state.sanitationEvaluation(static_cast<ParticipantManagement::SanitationEvaluation::inner_enum>(sanitationEvaluation.underlying()));
|
|
state.stateTime(sampleTime);
|
|
|
|
m_mutex.lock();
|
|
stateHistory.push_back(std::move(state));
|
|
m_mutex.unlock();
|
|
return true;
|
|
}
|
|
|
|
bool Participant::setOperatorAction(int action, int originatorId, qint64 sampleTime)
|
|
{
|
|
auto &stateHistory = m_dynamicData.stateHistory();
|
|
ParticipantManagement::StateInformation lastState;
|
|
|
|
// search for CombatReady state, ignore newState if it is older
|
|
for (const auto &s : stateHistory)
|
|
{
|
|
if (s.stateTime() > lastState.stateTime())
|
|
lastState = s;
|
|
}
|
|
|
|
ParticipantManagement::StateInformation state;
|
|
state.originatorId(originatorId);
|
|
state.originatorChargeTypeId(action);
|
|
state.originatorType(ProjectDataManagement::StateChangeOriginator::ObserverController);
|
|
state.vitality(lastState.vitality());
|
|
state.vulnerabilityBits(lastState.vulnerabilityBits());
|
|
state.vulnerabilityKindId(lastState.vulnerabilityKindId());
|
|
state.vulnerabilityState(lastState.vulnerabilityState());
|
|
// 08: Wound paused
|
|
// 35: Wound Continued
|
|
state.sanitationResult(ParticipantManagement::SanitationResult_def::NoEffect);
|
|
state.sanitationEvaluation(ParticipantManagement::SanitationEvaluation_def::NotApplicable);
|
|
state.stateTime(sampleTime);
|
|
|
|
m_mutex.lock();
|
|
stateHistory.push_back(std::move(state));
|
|
m_mutex.unlock();
|
|
return true;
|
|
}
|
|
|
|
bool Participant::setEquipmentEvent(int event, qint64 sampleTime)
|
|
{
|
|
|
|
auto &stateHistory = m_dynamicData.stateHistory();
|
|
ParticipantManagement::StateInformation lastState;
|
|
|
|
// search for CombatReady state, ignore newState if it is older
|
|
for (const auto &s : stateHistory)
|
|
{
|
|
if (s.stateTime() > lastState.stateTime())
|
|
lastState = s;
|
|
}
|
|
|
|
ParticipantManagement::StateInformation state;
|
|
state.originatorId(lastState.originatorId());
|
|
state.originatorChargeTypeId(event);
|
|
state.originatorType(ProjectDataManagement::StateChangeOriginator::ObserverController);
|
|
state.vitality(lastState.vitality());
|
|
state.sanitationResult(lastState.sanitationResult());
|
|
state.vulnerabilityBits(lastState.vulnerabilityBits());
|
|
state.vulnerabilityKindId(lastState.vulnerabilityKindId());
|
|
state.vulnerabilityState(lastState.vulnerabilityState());
|
|
state.stateTime(sampleTime);
|
|
|
|
m_mutex.lock();
|
|
stateHistory.push_back(std::move(state));
|
|
m_mutex.unlock();
|
|
return true;
|
|
|
|
}
|
|
|
|
bool Participant::setGearCharge(const TrainingAreaBase::GearCharge &charge, qint64 sampleTime)
|
|
{
|
|
// older than last complete reset (2s jitter allowed)
|
|
if (m_lastGearUsage - 2 * 1000 > sampleTime)
|
|
return false;
|
|
GearInformation gearInfo;
|
|
gearInfo.gearId(charge.gearId());
|
|
gearInfo.gearTypeId(charge.gearTypeId());
|
|
gearInfo.chargeTypeId(charge.chargeTypeId());
|
|
gearInfo.remain(charge.remain());
|
|
gearInfo.lastUpdate(sampleTime);
|
|
|
|
//set chargeCounting if needed
|
|
bool count = false;
|
|
for (const auto gi : m_dynamicData.gear())
|
|
{
|
|
if (gi.gearTypeId() == gearInfo.gearTypeId() && gi.chargeCounting())
|
|
count = true;
|
|
}
|
|
gearInfo.chargeCounting(count);
|
|
|
|
return setGearCharge(gearInfo);
|
|
}
|
|
|
|
bool Participant::setGearCharge(const GearInformation &gearInfo)
|
|
{
|
|
if (gearInfo.remain() < 0)
|
|
return true;
|
|
|
|
// check if charge.chargeType is already known
|
|
int index = indexByGearAndChargeId(gearInfo.gearId(), gearInfo.chargeTypeId());
|
|
int index_wanne=0;
|
|
// Hack for old systems which neither send gearTasCode/gearType nor gearSerialNumber/gearId
|
|
// 1 = Wanne, 2 = Turm, see TAB::send_to_dds.cpp
|
|
if (index < 0 && gearInfo.gearId() == 0) // no location info in EquipmentGearEvent
|
|
{
|
|
index = indexByGearAndChargeId(2, gearInfo.chargeTypeId()); // EquipmentGearEvent can only come from turret
|
|
index_wanne = indexByGearAndChargeId(1, gearInfo.chargeTypeId());
|
|
}
|
|
else if (index < 0 && gearInfo.gearId() == 2)
|
|
index = indexByGearAndChargeId(0, gearInfo.chargeTypeId());
|
|
|
|
if (index < 0) // not known but maybe a gear assignment (no charge info available yet)
|
|
index = indexByGearAndChargeId(gearInfo.gearId());
|
|
|
|
bool bRet = false;
|
|
if (index < 0)
|
|
{
|
|
m_mutex.lock();
|
|
m_dynamicData.gear().push_back(gearInfo); // new gear/charge combo - append
|
|
m_mutex.unlock();
|
|
bRet = true;
|
|
}
|
|
else
|
|
{
|
|
// already known, check for new data and update
|
|
m_mutex.lock();
|
|
auto &gi = m_dynamicData.gear()[index];
|
|
if (gi.lastUpdate() <= gearInfo.lastUpdate())
|
|
{
|
|
const bool chargeCounting = gi.chargeCounting();
|
|
const bool bAdjustTurretInfo = (gearInfo.gearId() == 0 && gi.gearId() == 2);
|
|
gi = gearInfo;
|
|
if (bAdjustTurretInfo)
|
|
{
|
|
int substr = m_dynamicData.gear()[index_wanne].remain();
|
|
INFO_LOG(m_logger) << "Adjust Turret - substracting index wanne " << substr;
|
|
if (gi.remain() >= substr)
|
|
gi.remain() = gi.remain() - m_dynamicData.gear()[index_wanne].remain();
|
|
INFO_LOG(m_logger) << "Turret remain " << gi.remain();
|
|
gi.gearId(2);
|
|
}
|
|
if (gearInfo.chargeCounting())
|
|
gi.chargeCounting(gearInfo.chargeCounting());
|
|
else
|
|
gi.chargeCounting(chargeCounting);
|
|
bRet = true;
|
|
}
|
|
m_mutex.unlock();
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
void Participant::setDynamicData(const DynamicParticipantData &data)
|
|
{
|
|
m_mutex.lock();
|
|
m_dynamicData = data;
|
|
|
|
m_lastGearUsage = m_dynamicData.sampleTime();
|
|
for (const auto &g : m_dynamicData.gear())
|
|
m_lastGearUsage = std::min(m_lastGearUsage, g.lastUpdate());
|
|
|
|
m_lastManipulationReset = m_dynamicData.sampleTime();
|
|
for (const auto &m : m_dynamicData.manipulation())
|
|
m_lastManipulationReset = std::min(m_lastManipulationReset, m.manipulationTime());
|
|
m_lastNbcState = m_lastManipulationReset;
|
|
|
|
m_lastSpecialSensorData = m_dynamicData.sampleTime();
|
|
m_dynamicData.sampleTime(0); // for publishing, see publishDynamicData
|
|
m_mutex.unlock();
|
|
}
|
|
|
|
void Participant::setMode(const ParticipantMode &data)
|
|
{
|
|
m_mutex.lock();
|
|
m_participantMode = data;
|
|
|
|
m_participantMode.sampleTime(0); // for publishing, see publishDynamicData
|
|
m_mutex.unlock();
|
|
}
|
|
|
|
bool Participant::isNewAssignStateValid(const ParticipantAssignState &newAssignState, int32_t equipmentNumber) const
|
|
{
|
|
const auto oldAssignState = m_participantData.assignState();
|
|
if (oldAssignState == newAssignState && m_participantData.equipmentNumber() == equipmentNumber)
|
|
return true;
|
|
|
|
switch (newAssignState.underlying())
|
|
{
|
|
case ParticipantAssignState::NotAssigned:
|
|
if (equipmentNumber)
|
|
{
|
|
WARNING_LOG(m_logger) << "Not assigned, but equipmentnumber is set";
|
|
return false;
|
|
}
|
|
break;
|
|
case ParticipantAssignState::AssignedWms:
|
|
if (oldAssignState != ParticipantAssignState::NotAssigned || equipmentNumber == 0)
|
|
{
|
|
// equipment number changed -> allow
|
|
if (oldAssignState == ParticipantAssignState::AssignedWms && equipmentNumber != 0)
|
|
return true;
|
|
WARNING_LOG(m_logger) << "Now assigned from WMS, but no equipmentnumber or old assign state != NotAssigned: "
|
|
<< equipmentNumber << ", " << newAssignState << ", " << oldAssignState;
|
|
return false;
|
|
}
|
|
break;
|
|
case ParticipantAssignState::HandoutWms:
|
|
if ((oldAssignState != ParticipantAssignState::NotAssigned &&
|
|
#ifdef GUEZ_MODE
|
|
oldAssignState != ParticipantAssignState::HandoutExcon &&
|
|
#endif
|
|
oldAssignState != ParticipantAssignState::AssignedWms) || equipmentNumber == 0)
|
|
{
|
|
// equipment number changed -> allow
|
|
if (oldAssignState == ParticipantAssignState::HandoutWms && equipmentNumber != 0)
|
|
return true;
|
|
WARNING_LOG(m_logger) << "Now assigned from WMS (handout), but no equipmentnumber or old assign state != NotAssigned/AssignedWms: "
|
|
<< equipmentNumber << ", " << newAssignState << ", " << oldAssignState;
|
|
return false;
|
|
}
|
|
break;
|
|
case ParticipantAssignState::HandoutExcon:
|
|
if ((oldAssignState != ParticipantAssignState::NotAssigned &&
|
|
oldAssignState != ParticipantAssignState::AssignedWms)
|
|
|| equipmentNumber == 0)
|
|
{
|
|
// equipment number changed -> allow
|
|
if ((oldAssignState == ParticipantAssignState::HandoutExcon ||
|
|
oldAssignState == ParticipantAssignState::ExconWmsOverruled) && equipmentNumber != 0)
|
|
return true;
|
|
// Assign state HandoutExcon + equipmentNumber = 0 -> reserved participant for EXCON in WH (WH must not touch it)
|
|
if (equipmentNumber == 0)
|
|
return true;
|
|
WARNING_LOG(m_logger) << "Now assigned from EXCON, but no equipmentnumber or old assign state != NotAssigned: "
|
|
<< equipmentNumber << ", " << newAssignState << ", " << oldAssignState;
|
|
return false;
|
|
}
|
|
break;
|
|
case ParticipantAssignState::ExconWmsOverruled:
|
|
// special case: warehouse doesn't like the equipment number set (ICD23, State C2)
|
|
if (oldAssignState == ParticipantAssignState::HandoutExcon &&
|
|
equipmentNumber == m_participantData.equipmentNumber())
|
|
return true;
|
|
if (oldAssignState != ParticipantAssignState::AssignedWms &&
|
|
oldAssignState != ParticipantAssignState::ExconWmsOverruled &&
|
|
oldAssignState != ParticipantAssignState::HandoutWms &&
|
|
equipmentNumber != 0)
|
|
{
|
|
WARNING_LOG(m_logger) << "Now assigned from ExconWmsOverruled, old assign state != AssignedWms or != HandoutWms or equipment number is set: "
|
|
<< equipmentNumber << ", " << newAssignState << ", " << oldAssignState;
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Participant::hasToBeChanged(const ParticipantManagement::Participant &data)
|
|
{
|
|
const ParticipantBase &baseData = data;
|
|
bool bRet = hasToBeChanged(baseData);
|
|
if (hasNewSuperiorId(data.superiorId()))
|
|
bRet = true;
|
|
if (hasNewInferiorStructure(data.inferiorIds()))
|
|
bRet = true;
|
|
if (data.identification() != m_participantData.identification())
|
|
{
|
|
bRet = true;
|
|
m_participantData.identification(data.identification());
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
bool Participant::hasToBeChanged(const ParticipantManagement::ParticipantBase &data)
|
|
{
|
|
DEBUG_LOG(m_logger) << "hasToBeChanged: " << data;
|
|
ParticipantManagement::ParticipantBase &curData = m_participantData;
|
|
bool hasChanges = (curData != data);
|
|
|
|
auto assignState = m_participantData.assignState();
|
|
if (assignState != data.assignState())
|
|
{
|
|
assignState = data.assignState();
|
|
hasChanges = true;
|
|
}
|
|
|
|
int newEquipmentNumber = 0;
|
|
// don't know why this is needed though
|
|
if (m_participantData.equipmentNumber().is_set())
|
|
newEquipmentNumber = m_participantData.equipmentNumber().get();
|
|
|
|
if (data.equipmentNumber().is_set() && m_participantData.equipmentNumber() != data.equipmentNumber())
|
|
{
|
|
newEquipmentNumber = data.equipmentNumber().get();
|
|
hasChanges = true;
|
|
}
|
|
|
|
// = Reserved for excon
|
|
if (!data.equipmentNumber().is_set() &&
|
|
assignState == ParticipantManagement::ParticipantAssignState::HandoutExcon)
|
|
{
|
|
newEquipmentNumber = 0;
|
|
hasChanges = true;
|
|
}
|
|
|
|
// wenn Assignment auf 'NotAssigned' oder 'ExconWmsOverruled' geändert wurde,
|
|
// muss die EquipmentNumber zurückgesetzt werden, egal was in data.equipmentNumber() steht
|
|
if (assignState == ParticipantManagement::ParticipantAssignState::NotAssigned ||
|
|
assignState == ParticipantManagement::ParticipantAssignState::ExconWmsOverruled)
|
|
{
|
|
if (m_participantData.equipmentNumber() != 0)
|
|
{
|
|
newEquipmentNumber = 0;
|
|
hasChanges = true;
|
|
}
|
|
}
|
|
|
|
if (hasChanges)
|
|
{
|
|
if (curData.typeId() != data.typeId())
|
|
m_bPublishPosition = !m_participantHandler->isUnitType(data.typeId());
|
|
|
|
const int oldEquipNo = curData.equipmentNumber().is_set() ? curData.equipmentNumber().get() : 0;
|
|
|
|
curData = data;
|
|
|
|
if (!updateEquipmentExerciseMapping(oldEquipNo, newEquipmentNumber))
|
|
{
|
|
curData.equipmentNumber().reset();
|
|
curData.assignState(ParticipantAssignState::NotAssigned);
|
|
}
|
|
}
|
|
|
|
return hasChanges;
|
|
}
|
|
|
|
bool Participant::hasNewSuperiorId(int32_t superiorId)
|
|
{
|
|
bool result = m_participantData.superiorId() != superiorId;
|
|
m_participantData.superiorId(superiorId);
|
|
|
|
if (result)
|
|
m_unitPosCalculator->onSuperiorChanged(id(), superiorId);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool Participant::hasNewInferiorStructure(std::vector<int32_t> inferiorIds)
|
|
{
|
|
// no need to sort m_inferiorIds - they're sorted since they are always filled with this function
|
|
std::sort(inferiorIds.begin(), inferiorIds.end());
|
|
|
|
if (m_participantData.inferiorIds() != inferiorIds)
|
|
{
|
|
m_participantData.inferiorIds(inferiorIds);
|
|
m_unitPosCalculator->onInferiorChanged(id(), m_participantData.inferiorIds());
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Participant::setOperationalState(const TrainingAreaBase::EquipmentOperationalState &operationalState)
|
|
{
|
|
m_mutex.lock();
|
|
bool bRet = false;
|
|
if (operationalState.isManipulation().is_set())
|
|
{
|
|
if (operationalState.equipmentFunctionId().is_set() &&
|
|
operationalState.isManipulation().get() &&
|
|
operationalState.sampleTime() > m_lastManipulationReset) // add if there is a new manipulation which is not outdated
|
|
{
|
|
removeManipulation(operationalState.equipmentFunctionId().get()); // precautionary
|
|
m_dynamicData.manipulation().emplace_back(operationalState.equipmentFunctionId().get(),
|
|
operationalState.sampleTime());
|
|
bRet = true;
|
|
}
|
|
else if (!operationalState.isManipulation().get()) // if manipulation is set to false, clean manipulations
|
|
{
|
|
if (m_lastManipulationReset < operationalState.sampleTime())
|
|
{
|
|
m_lastManipulationReset = operationalState.sampleTime();
|
|
cleanManipulations();
|
|
bRet = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (operationalState.nbcProtectionActive().is_set() &&
|
|
m_lastNbcState < operationalState.sampleTime())
|
|
{
|
|
m_dynamicData.hasNbcProtectionActive(operationalState.nbcProtectionActive().get());
|
|
m_dynamicData.hasNbcProtectionConfigured(operationalState.nbcProtectionActive().get());
|
|
|
|
m_lastNbcState = operationalState.sampleTime();
|
|
bRet = true;
|
|
}
|
|
m_mutex.unlock();
|
|
return bRet;
|
|
}
|
|
|
|
RegisterParticipantRequest Participant::toRegisterParticipantRequest() const
|
|
{
|
|
return RegisterParticipantRequest(id(),
|
|
equipmentNumber(),
|
|
assignState(),
|
|
m_participantData.identification(),
|
|
m_participantData.info());
|
|
}
|
|
|
|
bool Participant::publishPosition()
|
|
{
|
|
if (!m_bPublishPosition)
|
|
return true;
|
|
|
|
m_mutex.lock();
|
|
m_positionToPublish.participantId(id());
|
|
m_positionToPublish.participantTypeId(typeId());
|
|
m_positionToPublish.partyId(partyId());
|
|
m_mutex.unlock();
|
|
|
|
if (m_positionToPublish == m_positionPublished)
|
|
return true;
|
|
|
|
m_mutex.lock();
|
|
m_positionPublished = m_positionToPublish;
|
|
m_participantHandler->m_webSocketHandler->sendPosition(m_positionToPublish, equipmentNumber());
|
|
auto copy = m_positionPublished;
|
|
m_mutex.unlock();
|
|
|
|
return dts()->publish(copy);
|
|
}
|
|
|
|
bool Participant::publishDynamicData()
|
|
{
|
|
m_mutex.lock();
|
|
m_dynamicDataPublished.sampleTime(0); // for comparision
|
|
m_mutex.unlock();
|
|
if (m_dynamicData == m_dynamicDataPublished)
|
|
{
|
|
if ( m_dynamicData.designations().size() == m_dynamicDataPublished.designations().size() )
|
|
{
|
|
int i = 0;
|
|
bool equal = true;
|
|
for (LaserDesignation &laserDesignation : m_dynamicData.designations())
|
|
{
|
|
if (laserDesignation != m_dynamicDataPublished.designations().at(i))
|
|
{
|
|
equal = false;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (equal)
|
|
return true;
|
|
}
|
|
}
|
|
m_mutex.lock();
|
|
m_dynamicDataPublished = m_dynamicData;
|
|
m_dynamicDataPublished.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
|
auto copy = m_dynamicDataPublished;
|
|
m_mutex.unlock();
|
|
|
|
return dts()->publish(copy);
|
|
}
|
|
|
|
bool Participant::publishMode()
|
|
{
|
|
m_mutex.lock();
|
|
m_participantMode.sampleTime(0); // for comparision
|
|
m_mutex.unlock();
|
|
if (m_participantMode == m_participantModePublished)
|
|
return true;
|
|
m_mutex.lock();
|
|
m_participantModePublished = m_participantMode;
|
|
m_participantModePublished.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
|
auto copy = m_participantModePublished;
|
|
m_mutex.unlock();
|
|
|
|
return dts()->publish(copy);
|
|
}
|
|
|
|
bool Participant::publishParticipant()
|
|
{
|
|
m_mutex.lock();
|
|
m_participantPublished.sampleTime(0); // for comparision
|
|
m_mutex.unlock();
|
|
if (m_participantData == m_participantPublished)
|
|
return true;
|
|
m_mutex.lock();
|
|
m_participantPublished = m_participantData; // no swap!
|
|
m_participantPublished.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
|
auto copy = m_participantPublished;
|
|
m_mutex.unlock();
|
|
|
|
return dts()->publish(copy);
|
|
}
|
|
|
|
|
|
ParticipantManagement::Participant Participant::toDdsParticipant(const Database::PpmParticipant &data)
|
|
{
|
|
ParticipantManagement::Participant ret;
|
|
|
|
ret.id(data.id);
|
|
ret.partyId(data.partyId);
|
|
ret.hierarchyNumber(data.hierarchyNumber);
|
|
if (data.equipmentNumber)
|
|
ret.equipmentNumber(data.equipmentNumber);
|
|
ret.typeId(data.typeId);
|
|
ret.externalId(data.externalId);
|
|
ret.symbol(data.symbol.toStdString());
|
|
ret.name(data.name.toStdString());
|
|
ret.designator(data.designator.toStdString());
|
|
ret.tacticalIdentifier(data.tacticalIdentifier.toStdString());
|
|
ret.info(data.info.toStdString());
|
|
ret.assignState(data.assignState);
|
|
ret.isSimulated(data.isSimulated);
|
|
ret.isDeleted(data.isDeleted);
|
|
//ret.sampleTime();
|
|
ret.superiorId(data.superiorId);
|
|
//ret.inferiorIds();
|
|
ret.identification(data.identification.toStdString());
|
|
ret.properties(data.properties.toStdString());
|
|
|
|
return ret;
|
|
}
|
|
|
|
Database::PpmParticipant Participant::toDbParticipant() const
|
|
{
|
|
Database::PpmParticipant ret;
|
|
ret.id = m_participantData.id();
|
|
ret.assignState = m_participantData.assignState();
|
|
ret.partyId = m_participantData.partyId();
|
|
ret.typeId = m_participantData.typeId();
|
|
ret.externalId = m_participantData.externalId();
|
|
ret.designator = QString::fromStdString(m_participantData.designator());
|
|
ret.equipmentNumber = equipmentNumber();
|
|
ret.hierarchyNumber = m_participantData.hierarchyNumber();
|
|
ret.identification = QString::fromStdString(m_participantData.identification());
|
|
ret.info = QString::fromStdString(m_participantData.info());
|
|
ret.isDeleted = m_participantData.isDeleted();
|
|
ret.isSimulated = m_participantData.isSimulated();
|
|
ret.name = QString::fromStdString(m_participantData.name());
|
|
ret.superiorId = m_participantData.superiorId();
|
|
ret.symbol = QString::fromStdString(m_participantData.symbol());
|
|
ret.tacticalIdentifier = QString::fromStdString(m_participantData.tacticalIdentifier());
|
|
ret.properties = QString::fromStdString(m_participantData.properties());
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void Participant::removeManipulation(int32_t equipmentFunctionId)
|
|
{
|
|
size_t i = 0;
|
|
auto &manipulation = m_dynamicData.manipulation();
|
|
for (; i < manipulation.size(); ++i)
|
|
{
|
|
if (manipulation.at(i).equipmentFunctionId() == equipmentFunctionId)
|
|
break;
|
|
}
|
|
if (i >= manipulation.size()) // not found
|
|
return;
|
|
++i;
|
|
for (; i < manipulation.size(); ++i)
|
|
manipulation[i - 1] = manipulation.at(i);
|
|
manipulation.resize(manipulation.size() - 1);
|
|
}
|
|
|
|
void Participant::cleanManipulations()
|
|
{
|
|
std::vector<ManipulationInformation> currentManipulations;
|
|
currentManipulations.reserve(m_dynamicData.manipulation().size());
|
|
|
|
for (const ManipulationInformation &info : m_dynamicData.manipulation())
|
|
{
|
|
if (info.manipulationTime() >= m_lastManipulationReset)
|
|
currentManipulations.push_back(info);
|
|
}
|
|
m_dynamicData.manipulation(currentManipulations);
|
|
}
|
|
|
|
bool Participant::gearHasCharge(int32_t gearId) const
|
|
{
|
|
for (const GearInformation &gearInfo : m_dynamicData.gear())
|
|
{
|
|
if (gearInfo.gearId() == gearId)
|
|
return gearInfo.chargeTypeId() != -1; // -1 indicates, that there was no charge associated
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int32_t Participant::indexByGearAndChargeId(int32_t gearId, int32_t chargeTypeId) const
|
|
{
|
|
const auto &gears = m_dynamicData.gear();
|
|
for (size_t i = 0; i < gears.size(); ++i)
|
|
{
|
|
const auto &gear = gears.at(i);
|
|
if (gear.gearId() == gearId)
|
|
{
|
|
// search for gear with empty charge
|
|
if (chargeTypeId == -1 && gear.chargeTypeId() == -1)
|
|
return i;
|
|
// search for gear with specific charge
|
|
if (gear.chargeTypeId() == chargeTypeId)
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
qint64 Participant::currentTimeMSec() const
|
|
{
|
|
return m_participantHandler->currentTimeMSec();
|
|
}
|
|
|
|
std::shared_ptr<Interface::Dts> Participant::dts() const
|
|
{
|
|
return m_participantHandler->dts();
|
|
}
|
|
|
|
} // namespace ParticipantHandling
|
|
} // namespace ParticipantManagement
|