/** * Handler for player data * $Id$ * $HeadURL$ * $Author$ * Created by gr, SLSE, 2017-02-20 */ #include "handler_participant.h" #include "handler_building_data.h" #include #include #include namespace CentralEffectSimulation { HandlerParticipant::HandlerParticipant(const std::shared_ptr &ddsHandler, const std::shared_ptr &handlerBuildingData, int cheatingDistanceVehicle, int cheatingDistanceSoldier, QObject *parent) : QObject(parent) , m_ddsHandler(ddsHandler) , m_handlerBuildingData(handlerBuildingData) , m_cheatingDistanceVehicle(cheatingDistanceVehicle) , m_cheatingDistanceSoldier(cheatingDistanceSoldier) , m_logger(CentralEffectSimulation::getLogger("HandlerParticipant")) { } // end of ctor() //----------------------------------------------------------------------------- HandlerParticipant::~HandlerParticipant() { } // end of dtor() //----------------------------------------------------------------------------- bool HandlerParticipant::init() { auto dtcPpm = m_ddsHandler->dtcPpm(); INFO_LOG(m_logger) << "m_cheatingDistanceVehicle=" << m_cheatingDistanceVehicle << " m_cheatingDistanceSoldier=" << m_cheatingDistanceSoldier; // waitForHistorical... dtcPpm->waitForHistoricalDataType(1000); dtcPpm->waitForHistoricalDataParticipant(1000); dtcPpm->waitForHistoricalDataDynamicParticipantData(1000); dtcPpm->waitForHistoricalDataParticipantPosition(1000); // connect: connect(dtcPpm.get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged, this, &HandlerParticipant::onParticipantPositionChanged); connect(dtcPpm.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged, this, &HandlerParticipant::onDynamicParticipantDataChanged); connect(dtcPpm.get(), &ParticipantManagement::Interface::Dtc::participantChanged, this, &HandlerParticipant::onParticipantChanged); connect(dtcPpm.get(), &ParticipantManagement::Interface::Dtc::typeChanged, this, &HandlerParticipant::onTypeChanged); // init: { auto cb = [this](const ParticipantManagement::Type & data) { onTypeChanged(data, DataModification::eAdded); }; dtcPpm->types(cb); } { auto cb = [this](const ParticipantManagement::Participant & data) { onParticipantChanged(data, DataModification::eAdded); }; dtcPpm->participants(cb); } { auto cb = [this](const ParticipantManagement::DynamicParticipantData & data) { onDynamicParticipantDataChanged(data, DataModification::eAdded); }; dtcPpm->dynamicParticipantDatas(cb); } { auto cb = [this](const ParticipantManagement::ParticipantPosition & data) { onParticipantPositionChanged(data, DataModification::eAdded); }; dtcPpm->participantPositions(cb); } auto dtcTab = m_ddsHandler->dtcTab(); dtcTab->enableRestoreRadioReadiness(); connect(dtcTab.get(), &TrainingAreaBase::Interface::Dtc::restoreRadioReadinessChanged, this, &HandlerParticipant::onRestoreRadioReadinessChanged); INFO_LOG(m_logger) << "HandlerParticipant::init() finished. " << " m_positionsMap.size(): " << m_positionsMap.size(); return true; } // end of init() //----------------------------------------------------------------------------- void HandlerParticipant::onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType) { DEBUG_LOG(m_logger) << "onParticipantPositionChanged: " << data; if (modType == DataModification::eRemoved) { DEBUG_LOG(m_logger) << "m_participantsOutsideMap.remove participantId: " << data.participantId(); //m_participantsOutsideMap.remove(data.participantId()); } else { // [GUEZE-3102] Aufgesessene Teilnehmer bekommen den Schaden vom Fahrzeug, auf dem sie aufgesessen sind. if ( data.mountedOn().is_set()) { return; } int floorId = m_handlerBuildingData->getFloorIdFromRoomId(data.roomId()); int lastFloorId; CesParticipantData partPos(data); // update LtsPosition/LtsCoordinate: (created as new master, with Z, geo and utm) LtsCoordTrans::LtsCoordinate <sCoordRef = partPos.ltsCoordinate(); ltsCoordRef = LtsCoordTrans::LtsCoordinate(data.pos()); // ltsPosRef.setGeoPosition(data.pos(), 0.0); // hier wird 0.0 zu NaN umgewandelt ... // ltsPosRef.setZValueAccordingElevation(0.0); // hier wird implizit der LtsElevationManager genutzt // DEBUG_LOG(m_logger) << "- ltsPosRef: " << ltsPosRef; ltsCoordRef.replaceZValueByElevationIfValue(0.0); DEBUG_LOG(m_logger) << "- ltsCoordRef: " << ltsCoordRef; bool lastGeoPositionValid = false; auto it = m_positionsMap.find(partPos.participantId()); if (it != m_positionsMap.end()) { const CesParticipantData &partPosOld = *it; lastGeoPositionValid = partPosOld.lastPositionValid; lastFloorId = m_handlerBuildingData->getFloorIdFromRoomId(partPosOld.roomId()); partPos.vulnerabilityState = partPosOld.vulnerabilityState; partPos.lastGeoPosition = partPosOld.pos(); // save previous position partPos.lastPositionValid = true; if (floorId < 0 ) partPos.insideBuildingValue = false; else partPos.insideBuildingValue = true; // replace *it = partPos; } else { INFO_LOG(m_logger) << "m_positionsMap.insert=" << partPos; m_positionsMap.insert(data.participantId(), partPos); } // if (lastGeoPositionValid) { if (floorId < 0) { partPos.buildingId(0); partPos.roomId(0); DEBUG_LOG(m_logger) << "emit and insert newOutdoorPosition:" << partPos; m_positionsMap.insert(data.participantId(), partPos); emit newOutdoorPosition(partPos); if (lastFloorId > 0) emit participantLeavesBuilding(partPos.participantId()); } else { emit newIndoorPosition(partPos); } } DEBUG_LOG(m_logger) << "checkCheating m_positionsCheatingMap.size=" << m_positionsCheatingMap.size(); QHashIterator i(m_positionsCheatingMap); while (i.hasNext()) { i.next(); DEBUG_LOG(m_logger) << i.key() << ": " << i.value().participantId(); } if (m_positionsCheatingMap.contains(data.participantId())) { DEBUG_LOG(m_logger) << "checkCheatingPosition participantId=" << data.participantId(); checkCheatingPosition(data.participantId()); } INFO_LOG(m_logger) << "onParticipantPositionChanged()" << " participantId; " << data.participantId() << " participantTypeId: " << data.participantTypeId() << " partyId: " << data.partyId() << " vulnerabilityState: " << partPos.vulnerabilityState << " insideBuilding: " << partPos.insideBuilding(); INFO_LOG(m_logger) << partPos; } } // end of onParticipantPositionChanged() //----------------------------------------------------------------------------- void HandlerParticipant::onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType) { DEBUG_LOG(m_logger) << "onDynamicParticipantDataChanged"; if (modType == DataModification::eRemoved) return; CesParticipantData &participantPosition = m_positionsMap[data.participantId()]; // reference! // save vulnerabilityState in participantHandler ProjectDataManagement::VulnerabilityState newVulnerabilityState = ProjectDataManagement::VulnerabilityState_def::CombatReady; if (data.stateHistory().size() > 0) { const ParticipantManagement::StateInformation &vul = ParticipantManagement::youngestStateInformation(data.stateHistory()); newVulnerabilityState = vul.vulnerabilityState(); DEBUG_LOG(m_logger) << "newVulnerabilityState" << vul.vulnerabilityState(); if (newVulnerabilityState == ProjectDataManagement::VulnerabilityState_def::CombatReady) { emit participantDecontaminated(participantPosition.participantId()); DEBUG_LOG(m_logger) << "emit participantDecontaminated id=" << participantPosition.participantId(); } } if (participantPosition.vulnerabilityState != newVulnerabilityState) { checkCheating(data.participantId(), participantPosition, newVulnerabilityState); participantPosition.vulnerabilityState = newVulnerabilityState; emit newParticipantState(participantPosition); } } void HandlerParticipant::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType) { // Remove Participant: if (modType == DataModification::eRemoved || data.isDeleted()) { DEBUG_LOG(m_logger) << "onParticipantChanged m_positionsMap.remove id=" << data.id(); m_participantData.remove(data.id()); m_positionsMap.remove(data.id()); return; } // No OC in CES ParticipantManagement::TypeClass typeClass = typeClassFromTypeId(data.typeId()); if (typeClass == ParticipantManagement::TypeClass_def::SupportEntity || typeClass == ParticipantManagement::TypeClass_def::SupportUnit || typeClass == ParticipantManagement::TypeClass_def::Unit || typeClass == ParticipantManagement::TypeClass_def::Unknown) return; m_participantData[data.id()] = data; CesParticipantData &pos = m_positionsMap[data.id()]; pos.partyId(data.partyId()); pos.participantId(data.id()); pos.participantTypeId(data.typeId()); DEBUG_LOG(m_logger) << "onParticipantChanged" << " id=" << data.id() << " typeId=" << data.typeId() << " designator=" << data.designator(); } void HandlerParticipant::onTypeChanged(const ParticipantManagement::Type &data, DataModification modType) { if (modType == DataModification::eRemoved) return; m_typeMap.insert(data.id(), data.typeClass()); DEBUG_LOG(m_logger) << "m_typeMap.size()" << m_typeMap.size() << " equipmentTypeId=" << data.id() << " typeClass=" << data.typeClass(); } void HandlerParticipant::onRestoreRadioReadinessChanged(const TrainingAreaBase::RestoreRadioReadiness &data, DataModification modType) { // Remove Participant: if (modType == DataModification::eRemoved) { return; } auto dtcPpm = m_ddsHandler->dtcPpm(); int participantId = dtcPpm->participantIdByEquipmentNumber(data.equipmentNumber()); DEBUG_LOG(m_logger) << "onRestoreRadioReadinessChanged" << " data.equipmentNumber=" << data.equipmentNumber() << " participantId=" << participantId; emit restoreRadioReadinessChanged(participantId); auto partPos = m_positionsMap.value(participantId); if ( partPos.insideBuilding()) emit newIndoorPosition(partPos); else { partPos.buildingId(0); partPos.roomId(0); m_positionsMap.insert(participantId, partPos); emit newOutdoorPosition(partPos); } } QPolygonF HandlerParticipant::getParticipantStep(int participantId, int zone) const { QPolygonF result; auto it = m_positionsMap.find(participantId); if (it == m_positionsMap.end()) return {}; const CesParticipantData &partPos = it.value(); QPointF p1 = CentralEffectSimulation::geographic2Utm(partPos.lastGeoPosition, &zone); QPointF p2 = CentralEffectSimulation::geographic2Utm(partPos.pos(), &zone); //return {CentralEffectSimulation::geographic2Utm(partPos.lastGeoPosition, &zone), CentralEffectSimulation::geographic2Utm(partPos.pos(), &zone)}; result << p1 << p2 ; return result; } QPointF HandlerParticipant::getParticipantPositionUtm(int participantId, int zone) const { QPointF result = QPointF(); if (m_positionsMap.contains(participantId)) { const CesParticipantData &partPos = m_positionsMap.value(participantId); result = CentralEffectSimulation::geographic2Utm(partPos.pos(), &zone); } return result; } HandlerParticipant::CesParticipantData HandlerParticipant::getParticipantPosition(int participantId) const { return m_positionsMap.value(participantId); } QHash HandlerParticipant::positionsAircraft() const { QHash result; for (const HandlerParticipant::CesParticipantData &pos : m_positionsMap) { ParticipantManagement::TypeClass typeClass = typeClassFromTypeId(pos.participantTypeId()); if (typeClass != ParticipantManagement::TypeClass_def::Aircraft) continue; if (!m_participantData.contains(pos.participantId())) continue; result.insert(pos.participantId(), pos); } return result; } QVector HandlerParticipant::getParticipantsBuilding(const int32_t buildingId) const { QVector result; DEBUG_LOG(m_logger) << "getParticipantsBuilding:" << buildingId; for (const HandlerParticipant::CesParticipantData &pos : m_positionsMap) { if (buildingId == pos.buildingId()) { DEBUG_LOG(m_logger) << "result.append " << pos.participantId(); result.append(pos.participantId()); } } return result; } bool HandlerParticipant::handleCheating(const ParticipantManagement::TypeClass typeClass, const ProjectDataManagement::VulnerabilityState newVulnerabilityState) { DEBUG_LOG(m_logger) << "handleCheating typeClass=" << typeClass << " newVulnerabilityState=" << newVulnerabilityState; // unknown is necessary for the initialization phase if (typeClass == ParticipantManagement::TypeClass::Unknown) { DEBUG_LOG(m_logger) << "handle Cheating for Unknown"; return true; } if (typeClass == ParticipantManagement::TypeClass::Human) { DEBUG_LOG(m_logger) << "handle Cheating for Human"; if (newVulnerabilityState >= ProjectDataManagement::VulnerabilityState::MediumDamage) return true; } if (typeClass == ParticipantManagement::TypeClass::GroundVehicle || typeClass == ParticipantManagement::TypeClass::WeaponSystem || typeClass == ParticipantManagement::TypeClass::VehicleWithGear) { DEBUG_LOG(m_logger) << "handle Cheating for Vehicle"; if (newVulnerabilityState == ProjectDataManagement::VulnerabilityState::MobilityKill || newVulnerabilityState == ProjectDataManagement::VulnerabilityState::VisibleMobilityKill) return true; } return false; } // if no participantPosition has yet arrived, the participantId in participantPosition is 0 void HandlerParticipant::checkCheating(const int participantId, const CesParticipantData &participantPosition, const ProjectDataManagement::VulnerabilityState newVulnerabilityState) { DEBUG_LOG(m_logger) << "checkCheating state =" << newVulnerabilityState << " participantId=" << participantId; if (!m_typeMap.contains(participantPosition.participantTypeId())) WARNING_LOG(m_logger) << "!m_typeMap.contains(" << participantPosition.participantTypeId() << ")"; ParticipantManagement::TypeClass typeClass = m_typeMap[participantPosition.participantTypeId()]; if (handleCheating(typeClass, newVulnerabilityState)) { if (!m_positionsCheatingMap.contains(participantId)) { DEBUG_LOG(m_logger) << "checkCheating insert id= " << participantId; m_positionsCheatingMap.insert(participantId, participantPosition); } } else { if (newVulnerabilityState == ProjectDataManagement::VulnerabilityState::CombatReady) { DEBUG_LOG(m_logger) << "checkCheating remove id= " << participantId; m_positionsCheatingMap.remove(participantId); } } } void HandlerParticipant::checkCheatingPosition(const int participantId) { DEBUG_LOG(m_logger) << "checkCheatingPosition id= " << participantId; CesParticipantData posMobilityKill = m_positionsCheatingMap[participantId]; CesParticipantData posActual = m_positionsMap[participantId]; ParticipantManagement::TypeClass typeClass = m_typeMap[participantId]; if (!posActual.insideWlsArea()) { DEBUG_LOG(m_logger) << "position participantId=" << participantId << " not insideWlsArea"; return; } // Check, if valid position is available if (posMobilityKill.participantId() == 0) { DEBUG_LOG(m_logger) << "position participantId=" << participantId << " not valid"; m_positionsCheatingMap.insert(participantId, posActual); return; } QPointF posUtmMobilityKill = CentralEffectSimulation::geographic2Utm(posMobilityKill.pos()); QPointF posUtmActual = CentralEffectSimulation::geographic2Utm(posActual.pos()); DEBUG_LOG(m_logger) << "posUtmMobilityKill=" << posUtmMobilityKill.rx() << "/" << posUtmMobilityKill.ry(); DEBUG_LOG(m_logger) << "posUtmActual=" << posUtmActual.rx() << "/" << posUtmActual.ry(); qreal distance = QLineF(posUtmMobilityKill, posUtmActual).length(); int cheatingDistance; if (typeClass == ParticipantManagement::TypeClass::Human) cheatingDistance = m_cheatingDistanceSoldier; else cheatingDistance = m_cheatingDistanceVehicle; DEBUG_LOG(m_logger) << "distance=" << distance; if (distance > cheatingDistance) { DEBUG_LOG(m_logger) << " Send Manipulation to id= and save new Cheating Position" << participantId; m_positionsCheatingMap.insert(participantId, posActual); sendBeStillWarning(participantId); } } void HandlerParticipant::onSendParticipantBeStillWarningReply(const Core::FunctionReplyObject &replyObject) { //if (replyObject.error()) // WARNING_LOG(m_logger) << "Can not send hit on participant to training area: " << replyObject(); //else DEBUG_LOG(m_logger) << "onSendParticipantBeStillWarningReply for id " << replyObject.id() << " success"; } void HandlerParticipant::sendBeStillWarning(const int32_t participantId) { TrainingAreaBase::SendParticipantBeStillWarningRequest pba; pba.equipmentNumber(m_ddsHandler->participantId2EquipNo(participantId)); pba.participantId(participantId); pba.data(0); m_ddsHandler->ftcTab()->sendParticipantBeStillWarningRequest(pba, this); } void HandlerParticipant::onModifyStateReply(const Core::FunctionReplyObject &reply) { if (reply.error()) ERROR_LOG(m_logger) << "onModifyStateReply for id " << reply.id() << " failure"; else DEBUG_LOG(m_logger) << "onModifyStateReply for id " << reply.id() << " success"; } void HandlerParticipant::modifyStateRequest( const int &participantId, const ProjectDataManagement::VulnerabilityState &state, const int &kind, const int &vitality ) { std::vector participantIds; participantIds.push_back(participantId); ParticipantManagement::ModifyStateRequest msr; msr.participantIds(participantIds); msr.vulnerabilityState(state); msr.vulnerabilityKind(kind); msr.vitality(vitality); m_ddsHandler->ftcPpm()->modifyStateRequest(msr, this); } long HandlerParticipant::getDirection(int originatorParticipantId, int targetParticipantId) { CesParticipantData originatorPos = m_positionsMap[originatorParticipantId]; CesParticipantData targetPos = m_positionsMap[targetParticipantId]; const Core::GeoPosition2D originatorGeoPos = originatorPos.pos(); const Core::GeoPosition2D targetGeoPos = targetPos.pos(); int zone = -1; const QPointF originatorPosUtm = CentralEffectSimulation::geographic2Utm(originatorGeoPos, &zone); const QPointF targetPosUtm = CentralEffectSimulation::geographic2Utm(targetGeoPos, zone); const QLineF line(originatorPosUtm, targetPosUtm); DEBUG_LOG(m_logger) << "originatorPosUtm=" << originatorPosUtm.x() << " / " << originatorPosUtm.y(); DEBUG_LOG(m_logger) << "targetPosUtm=" << targetPosUtm.x() << " / " << targetPosUtm.y(); DEBUG_LOG(m_logger) << "getDirection=" << (static_cast(line.angle()) + 270) % 360 * 100; return (static_cast(line.angle()) + 270) % 360 * 100; } long HandlerParticipant::getDistance(int originatorParticipantId, int targetParticipantId) { CesParticipantData originatorPos = m_positionsMap[originatorParticipantId]; CesParticipantData targetPos = m_positionsMap[targetParticipantId]; const Core::GeoPosition2D originatorGeoPos = originatorPos.pos(); const Core::GeoPosition2D targetGeoPos = targetPos.pos(); int zone = -1; const QPointF originatorPosUtm = CentralEffectSimulation::geographic2Utm(originatorGeoPos, &zone); const QPointF targetPosUtm = CentralEffectSimulation::geographic2Utm(targetGeoPos, zone); const QLineF line(originatorPosUtm, targetPosUtm); DEBUG_LOG(m_logger) << "getDistance=" << line.length(); return static_cast(line.length()); } int HandlerParticipant::getParticipantId(int equipentNumber) { // QHash m_participantData; QHashIterator i(m_participantData); while (i.hasNext()) { i.next(); if (i.value().equipmentNumber() == equipentNumber) return i.value().id(); } return 0; } int HandlerParticipant::getEquipmentNumber(int participantId) const { return m_ddsHandler->participantId2EquipNo(participantId); } void HandlerParticipant::setNotfightMode ( const int participantId, const bool notfightMode) { CesParticipantData participantData = m_positionsMap.value(participantId); participantData.notfightMode = notfightMode; INFO_LOG(m_logger) << "setNotfightMode m_positionsMap.insert=" << participantData; m_positionsMap.insert ( participantId,participantData ); emit newNotfightMode(participantData); } std::ostream &operator<<(std::ostream &stream, const HandlerParticipant::CesParticipantData &value) { stream << "CesParticipantData(" << ", lastGeoPosition = " << value.lastGeoPosition << ", lastPositionValid = " << value.lastPositionValid << ", ltsCoordinate = " << value.ltsCoordinate() << ", insideWlsArea = " << value.insideWlsArea() << ", insideBuilding = " << value.insideBuilding() << ", buildingId = " << value.buildingId() << ", notfightMode = " << value.notfightMode << ", partyId = " << value.partyId() << ", vulnerabilityState= " << value.vulnerabilityState << ", participantTypeId = " << value.participantTypeId() << ", participantId = " << value.participantId() << ")"; return stream; } } // namespace CentralEffectSimulation