new_docker_build.sh gains Group 12 (212 GUI/Data plugins); fixes LtsUtilsGuiDds visibility (LTO-stripped exports), LtsProjectionWorkstation unity name shadow, 6 unity-off dirs (dup file-scope statics, ddsftc INTERFACE sources) and reconfigures BUILD_FILTERMANAGEMENT/BUILD_PLUGINS_SERVICEMONITOR=ON
1142 lines
39 KiB
C++
Executable File
1142 lines
39 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 <QtCore/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::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.has_value() ? newPosition.position.moutObjectId.get() : 0;
|
|
m_positionToPublish.roomId = newPosition.position.moutRoomId.has_value() ? 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.has_value())
|
|
{
|
|
// list of new mounted participants
|
|
std::vector<int32_t> newMountedParticipantIds;
|
|
// list of already mounted participants
|
|
std::vector<int32_t> currentMountedParticipantIds;
|
|
if (m_positionPublished.mountedParticipants.has_value())
|
|
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.has_value()))
|
|
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::VulnerabilityState_CombatReady &&
|
|
s.stateTime > newState.sampleTime)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::bitset<sizeof(newState.vulnerabilityBits) * 8> bits(newState.vulnerabilityBits);
|
|
bits.set(static_cast<int>(newState.vulnerabilityState));
|
|
|
|
QStringList bitsList;
|
|
for (int i = (int)ProjectDataManagement::VulnerabilityState::VulnerabilityState_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::VulnerabilityState_TemporarySeverance &&
|
|
newState.vulnerabilityState != ProjectDataManagement::VulnerabilityState::VulnerabilityState_NearMiss &&
|
|
newState.vulnerabilityState != ProjectDataManagement::VulnerabilityState::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::VulnerabilityState_CatastrophicKill; i > 0; --i)
|
|
{
|
|
if (bits.test(i))
|
|
{
|
|
mainVulState = static_cast<ProjectDataManagement::VulnerabilityState>(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::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
|
|
<< "\nvuln now: " << (int)mainVulState
|
|
<< "\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);
|
|
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::VulnerabilityState_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::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>(sanEvaluationVal);
|
|
sanResult = static_cast<SanitationResult>(sanResultVal);
|
|
}
|
|
#endif
|
|
|
|
//new state Temp Vis Damage
|
|
if(newState.vulnerabilityState == ProjectDataManagement::VulnerabilityState::VulnerabilityState_VisibleWeaponSystemDamage ||
|
|
newState.vulnerabilityState == ProjectDataManagement::VulnerabilityState::VulnerabilityState_NearMiss ||
|
|
newState.vulnerabilityState == ProjectDataManagement::VulnerabilityState::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;
|
|
sanEvaluation = lastState.sanitationEvaluation;
|
|
}
|
|
|
|
|
|
if(mainVulState == ProjectDataManagement::VulnerabilityState::VulnerabilityState_CombatReady ||
|
|
newState.originatorType == ProjectDataManagement::StateChangeOriginator::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::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 = static_cast<int>(qualification);
|
|
state.originatorType = ProjectDataManagement::StateChangeOriginator::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>(sanitationResult);
|
|
state.sanitationEvaluation = static_cast<ParticipantManagement::SanitationEvaluation>(sanitationEvaluation);
|
|
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::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::NoEffect;
|
|
state.sanitationEvaluation = ParticipantManagement::SanitationEvaluation::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::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, static_cast<qint64>(g.lastUpdate));
|
|
|
|
m_lastManipulationReset = m_dynamicData.sampleTime;
|
|
for (const auto &m : m_dynamicData.manipulation)
|
|
m_lastManipulationReset = std::min(m_lastManipulationReset, static_cast<qint64>(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)
|
|
{
|
|
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.has_value())
|
|
newEquipmentNumber = m_participantData.equipmentNumber.get();
|
|
|
|
if (data.equipmentNumber.has_value() && m_participantData.equipmentNumber != data.equipmentNumber)
|
|
{
|
|
newEquipmentNumber = data.equipmentNumber.get();
|
|
hasChanges = true;
|
|
}
|
|
|
|
// = Reserved for excon
|
|
if (!data.equipmentNumber.has_value() &&
|
|
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.has_value() ? 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.has_value())
|
|
{
|
|
if (operationalState.equipmentFunctionId.has_value() &&
|
|
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.has_value() &&
|
|
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
|