/** * 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 { ParticipantManagement::TypeClass typeClass = typeClassFromTypeId(data.participantTypeId); if (typeClass == ParticipantManagement::TypeClass::SupportEntity || typeClass == ParticipantManagement::TypeClass::SupportUnit || typeClass == ParticipantManagement::TypeClass::Unit || typeClass == ParticipantManagement::TypeClass::Unknown) return; // [GUEZE-3102] Aufgesessene Teilnehmer bekommen den Schaden vom Fahrzeug, auf dem sie aufgesessen sind. if (data.mountedOn.has_value()) 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::VulnerabilityState_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::VulnerabilityState_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::SupportEntity || typeClass == ParticipantManagement::TypeClass::SupportUnit || typeClass == ParticipantManagement::TypeClass::Unit || typeClass == ParticipantManagement::TypeClass::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::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::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::VulnerabilityState_MobilityKill || newVulnerabilityState == ProjectDataManagement::VulnerabilityState::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::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