/** * Handler for player data * $Id$ * $HeadURL$ * $Author$ * Created by hjl, SLSE, 2017-02-20 */ #include "handler_participant_building.h" #include #include #define PERCENT_100 100 namespace CesParticipantBuildings { HandlerParticipantBuilding::HandlerParticipantBuilding(const std::shared_ptr &ddsHandler, const std::shared_ptr &participantHandler, const std::shared_ptr &handlerBuildingData, QObject *parent) : QObject(parent) , m_ddsHandler(ddsHandler) , m_handlerParticipant(participantHandler) , m_handlerBuildingData(handlerBuildingData) , m_buildingStates() , m_requestMap() , m_timer(new QTimer(this)) , m_logger(CentralEffectSimulation::getLogger("Plugin.ParticipantBuildings.HandlerParticipantBuilding")) { m_timer->setSingleShot(true); connect(m_timer, &QTimer::timeout, this, &HandlerParticipantBuilding::sendFtcCesHitRequestTimeout); } // end of ctor() //----------------------------------------------------------------------------- HandlerParticipantBuilding::~HandlerParticipantBuilding() { } // end of dtor() //----------------------------------------------------------------------------- bool HandlerParticipantBuilding::init() { auto dtcBld = m_ddsHandler->dtcBld(); dtcBld->waitForHistoricalDataBuildingState(1000); connect(dtcBld.get(), &Buildings::Interface::Dtc::buildingStateChanged, this, &HandlerParticipantBuilding::onBuildingStateChanged); // Get 'static' data for all buildingStates { auto cb = [this](const Buildings::BuildingState & bs) { onBuildingStateChanged(bs, DataModification::eAdded); }; if (!dtcBld->buildingStates(cb)) return false; } return true; } // end of init() //----------------------------------------------------------------------------- int HandlerParticipantBuilding::getDamagePercentFromBuilding(const int buildingId) const { DEBUG_LOG(m_logger) << "getDamagePercentFromBuilding buildingId=" << buildingId; auto it = m_buildingStates.find(buildingId); return it != m_buildingStates.end() ? it.value().damagePercent() : 0; } int HandlerParticipantBuilding::getDamagePercentFromRoom(const int roomId) const { //int buildingId = m_handlerBuildingData->getBuildingIdFromRoomId(roomId); int buildingId; m_ddsHandler->dtcIsm()->getBuildingId(roomId, buildingId); auto it = m_roomIdDamageState.find(roomId); // Exception: // if a building has failed completely, not all individual rooms are set as failed DEBUG_LOG(m_logger) << "getDamagePercentFromBuilding=" << getDamagePercentFromBuilding(buildingId) << " buildingId=" << buildingId << " roomId=" << roomId; if (buildingId < 0) return -1; if (getDamagePercentFromBuilding(buildingId) == PERCENT_100) { DEBUG_LOG(m_logger) << "return PERCENT_100:" << PERCENT_100; return PERCENT_100; } return it != m_roomIdDamageState.end() ? it.value().damagePercent : 0; } void HandlerParticipantBuilding::onSendCesHitReply(const Core::FunctionReplyObject &replyObject) { //if (replyObject.error()) // WARNING_LOG(m_logger) << "Can not send hit on participant to training area: " << replyObject(); //else m_requestMap.remove(replyObject.id()); DEBUG_LOG(m_logger) << "onSendCesHitReply for id " << replyObject.id() << " success" << " m_requestMap.remove(" << replyObject.id() << ")" << " m_requestMap.size=" << m_requestMap.size(); } // /////////////////////////////////// // B L D (Buildings) // /////////////////////////////////// void HandlerParticipantBuilding::onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType) { if (modType == DataModification::eRemoved) { m_buildingStates.remove(data.id()); return; } DEBUG_LOG(m_logger) << "Got BuildingState originatorParticipantId=" << data.originatorParticipantId() << ", aesId = " << data.aesId() << ", chargeTypeId = " << data.chargeTypeId() << ", sampleTime = " << data.sampleTime() << ", CountRooms =" << data.roomStates().size() << ", structureElementId=" << data.structureElementId() << ", assetId=" << data.assetId() << ", roomStates.size=" << data.roomStates().size() << ", damagePercent" << data.damagePercent(); if ( (data.originatorParticipantId() == 0) && (data.aesId() == 0) && (data.chargeTypeId()==0)) { DEBUG_LOG(m_logger) << "Not valid return "; return; } // fill m_roomIdDamageState RoomState rs; rs.buildingId = data.id(); m_buildingStates.insert(data.id(), data); DEBUG_LOG(m_logger) << "m_buildingStates.insert id=" << data.id() << " aesId=" << data.aesId() << " name=" << data.name(); for (const Buildings::RoomState &roomState : data.roomStates()) { rs.damagePercent = roomState.damagePercent(); m_roomIdDamageState.insert(roomState.id(), rs); DEBUG_LOG(m_logger) << "m_roomIdDamageState.insert" << " RoomId = " << roomState.id() << ", BuildingId = " << data.id() << ", destruction = " << roomState.damagePercent(); } // init: remove all rooms from Map if (data.damagePercent() == 0) { auto it = m_roomIdDamageState.begin(); while (it != m_roomIdDamageState.end()) { if (it.value().buildingId == data.id()) it = m_roomIdDamageState.erase(it); else ++it; } return; } const auto participantsMap = m_handlerParticipant->positions(); for (const Buildings::RoomState &roomState : data.roomStates()) { if (roomState.damagePercent() <= 0) continue; // no effect should not burden the radio if (roomState.remainingEffectPercent() == 0) continue; DEBUG_LOG(m_logger) << " RoomId[" << roomState.id() << "]:" << " remainingEffectPercent = " << roomState.remainingEffectPercent() << " roomState.damagePercent()=" << roomState.damagePercent() << " roomState.remainingEffectPercent()=" << roomState.remainingEffectPercent(); // search for participants in each room: // if participant in room sendCESHit to TAB for (const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPos : participantsMap) { const int participantId = participantPos.participantId(); if (participantPos.roomId() != roomState.id()) continue; if (participantPos.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::CatastrophicKill) continue; const int equipNo = m_ddsHandler->participantId2EquipNo(participantId); if (equipNo <= 0) continue; if (m_handlerParticipant->isOutdated(participantPos)) continue; DEBUG_LOG(m_logger) << " participantId = " << participantId << " roomId = " << participantPos.roomId() << " roomState.id=" << roomState.id() << " participantPos.vulnerabilityState=" << participantPos.vulnerabilityState << " equipNo=" << m_ddsHandler->participantId2EquipNo(participantId) << " isOutdated=" << m_handlerParticipant->isOutdated(participantPos); DEBUG_LOG(m_logger) << "sendCesHitToParticipant"; sendCesHitToParticipant(data, participantId, roomState.remainingEffectPercent()); } } m_buildingStates.insert(data.id(), data); if (!m_timer->isActive() && !m_requestMap.isEmpty()) m_timer->start(1000); emit newBuildingState(data.id()); } void HandlerParticipantBuilding::sendCesHitToParticipant(const Buildings::BuildingState &data, const int32_t participantId, const int32_t remainingEffectPercent) { const int equipNo = m_ddsHandler->participantId2EquipNo(participantId); const QHash participantsMap = m_handlerParticipant->positions(); const int originatorEquipNo = m_ddsHandler->participantId2EquipNo(data.originatorParticipantId()); CentralEffectSimulation::HandlerParticipant::CesParticipantData participantPos = participantsMap.value(participantId); const ProjectDataManagement::EventType eventType = ProjectDataManagement::EventType_def::HitBuilding; AreaEffectSimulation::AesItem aesItem; bool itemAvailable = m_ddsHandler->dtcAes()->aesItemFromId(data.aesId(), aesItem); if (itemAvailable) DEBUG_LOG(m_logger) << "partyId=" << aesItem.partyId() << " chargeTypeId=" << aesItem.chargeStruct().chargeTypeId() << " duration=" << aesItem.effectDuration(); // mineFieldBitIndex wird als reserve1 uegertragen und hier wird die Wirkdauer uebertragen. const int duration = aesItem.effectDuration() / 1000; //int32_t legacyChargeTypeId = 0; //const ProjectDataManagement::FuseType fuseType = m_ddsHandler->dtcAes()->explosionCluster(aesItem.id()).fuseType(); const int chargeTypeId = itemAvailable ? aesItem.chargeStruct().chargeTypeId() : data.chargeTypeId(); // legacyChargeTypeId = m_ddsHandler->getLegacyIdFromChargeTypeId(chargeTypeId, fuseType); // NOTE: igniterTypeId/IgniterFunction = 0 as long as BuildingState does not contain values AreaEffectSimulation::ChargeStruct chargeStruct = { data.chargeTypeId(),0,0}; if (itemAvailable) chargeStruct = aesItem.chargeStruct(); int remainTasCodeIndirect = m_ddsHandler->remainingTasCode(chargeStruct); DEBUG_LOG(m_logger) << " ftc sendCESHit to Participant equipNo = " << equipNo << " participantId=" << participantId << " chargeTypeId=" << data.chargeTypeId() << " originatorEquipNo=" << originatorEquipNo << " remainingEffectPercent=" << remainingEffectPercent << " remainTasCodeIndirect=" << remainTasCodeIndirect << " eventType=" << eventType; const TrainingAreaBase::TabPosition pos(participantPos.pos(), participantPos.reportingSource(), participantPos.buildingId(), participantPos.roomId()); // Bei Nebel soll die Weste nur einmal piepen und nicht regelmaessig. Das wird mit Wirkung = 3 uebertragen // In fog, the waistcoat should only beep once and not regularly. This is transmitted with effect = 3 // int effect; // if (m_ddsHandler->isSmoke(chargeTypeId)) // effect = 3; // else // effect = 2; TrainingAreaBase::SendCesHitRequest requestTab; requestTab.aesId(data.aesId()); //requestTab.chargeTypeId(legacyChargeTypeId > 0 ? legacyChargeTypeId : chargeTypeId); requestTab.chargeTypeId(chargeTypeId); requestTab.effectTime(data.sampleTime()); requestTab.equipmentNumber(equipNo); requestTab.eventType(eventType); requestTab.mineId(duration); requestTab.originatorEquipmentNumber(originatorEquipNo); requestTab.participantId(participantId); int32_t partyId = 0; if ( aesItem.partyId().is_set()) partyId = aesItem.partyId().get(); requestTab.partyId(partyId); requestTab.position(pos); // Same like direct Hit // if (aesItem.id() > 0) // { // NOTICE_LOG(m_logger) << "remainEffectPercent Wirksimulation remainEffectPercent=" << remainTasCodeIndirect; // requestTab.remainEffectPercent(remainTasCodeIndirect); // } // else { DEBUG_LOG(m_logger) << "direkter Beschuss remainEffectPercent=" << remainingEffectPercent; requestTab.remainEffectPercent(remainingEffectPercent); } m_requestMap.insert(participantId, requestTab); } void HandlerParticipantBuilding::sendFtcCesHitRequestTimeout() { auto ftcTab = m_ddsHandler->ftcTab(); for (const TrainingAreaBase::SendCesHitRequest &hr : qAsConst(m_requestMap)) { DEBUG_LOG(m_logger) << "sendFtcCesHitRequest: " << hr; ftcTab->sendCesHitRequest(hr, this); } m_requestMap.clear(); } } // namespace CesParticipantBuildings