/** * @RDE_HEADER@ * Custom ppm functions (extends tab_db_impl.cpp/.h) * $Id$ * $HeadURL$ * $Author$ */ #include "ppm_common.h" #include #include #include namespace ParticipantManagement { StateInformation youngestStateInformation(const std::vector &stateList, bool bSkipVbgGreaterCatastrophicKill, bool bSkipSanitation, bool debug) { std::shared_ptr _(nullptr, [debug](int *) { if (debug) qWarning() << "##############################################"; }); if (debug) qWarning() << "########## youngestStateInformation ##########"; ParticipantManagement::StateInformation ret; // rtiddsgen 7.7 generates plain public members (no setters) and prefixed // PDM enumerators (commit be912de9d resolved duplicate enumerators). ret.vulnerabilityState = ProjectDataManagement::VulnerabilityState::VulnerabilityState_NotReady; if (stateList.empty()) { if (debug) qWarning() << ">> stateList empty! not ready"; return ret; } // bool readyToDebug = false; // for (const ParticipantManagement::StateInformation &si : std::as_const(stateList)) // { // if (si.originatorId() == 0 // && si.originatorType() == ProjectDataManagement::StateChangeOriginator::ExerciseControl // && (si.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::CatastrophicKill // || si.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::CombatReady) // ) // readyToDebug = true; // } /* NOTE: Participant::setState in PPM doesn't respect the vulnId sent by the TNE, but instead sets it to * the highest vuln (ignoring TemporarySeverance, NearMiss and HitWithNoEffect!) that was found in * the vulnerabilityBits. So the latest state in the history is always the state we are looking for. * NOTE: StateInformation's stateTime max resolution is seconds instead of milliseconds * NOTE: StateInformations can have the same stateTime, which means a CombatReady might be incorrectly * chosen because it has the same stateTime as a CatastrophicKill - if not sorted by time *and* state */ std::vector sortedStateList(stateList); // copy list // sort list by sample time, desc (highest time = youngest) std::sort(sortedStateList.begin(), sortedStateList.end(), [/*&debug,readyToDebug*/](const ParticipantManagement::StateInformation &left, const ParticipantManagement::StateInformation &right) { if (left.stateTime == right.stateTime && left.vulnerabilityState != right.vulnerabilityState) { // if (readyToDebug) // debug = true; // qWarning() << "WARNING: StateInformation with state" << (int)left.vulnerabilityState().underlying() << "has the same stateTime as StateInformation with state" << (int)right.vulnerabilityState().underlying(); // sort by state if time is the same (higher state = winner) return (left.vulnerabilityState > right.vulnerabilityState); } return (left.stateTime > right.stateTime); }); if (debug) { qWarning() << ">> printing all SIs"; for (const ParticipantManagement::StateInformation &si : std::as_const(sortedStateList)) qWarning() << ">>>> si" << "siVulnId" << (uint8_t)si.vulnerabilityState << "bits" << si.vulnerabilityBits << "time" << si.stateTime; qWarning() << ">> checking SIs"; } for (const ParticipantManagement::StateInformation &si : std::as_const(sortedStateList)) { const uint8_t siVulnId = static_cast(si.vulnerabilityState); if (debug) { qWarning() << "MWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMW"; qWarning() << ">>>> si" << "siVulnId" << siVulnId; } // we're only interested in 'visible' VBGs, don't care about near miss etc. here if (bSkipVbgGreaterCatastrophicKill && si.vulnerabilityState > ProjectDataManagement::VulnerabilityState::VulnerabilityState_CatastrophicKill) { if (debug) qWarning() << ">>>> vulnId is higher than CK!"; continue; } if (bSkipSanitation && si.originatorType == ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_Sanitation) { if (debug) qWarning() << ">>>> is sanitation!"; continue; } if (debug) qWarning() << ">>>> match! done!"; return si; } if (debug) qWarning() << ">> no state found" << "bSkipVbgGreaterCatastrophicKill" << bSkipVbgGreaterCatastrophicKill << "bSkipSanitation" << bSkipSanitation; return ret; } StateInformation youngestRealStateInformation(const std::vector &stateList, bool bSkipVbgGreaterCatastrophicKill) { if (stateList.size() == 0) { ParticipantManagement::StateInformation ret; ret.vulnerabilityState = ProjectDataManagement::VulnerabilityState::VulnerabilityState_NotReady; return ret; } StateInformation youngestState = youngestStateInformation(stateList); size_t youngest = 0; for (size_t i = 1; i < stateList.size(); ++i) { const auto &tCurrent = stateList.at(i).stateTime; const auto &tYoungest = stateList.at(youngest).stateTime; // we're only interested in 'visible' VBGs, don't care about near miss etc. here if (bSkipVbgGreaterCatastrophicKill && stateList.at(i).vulnerabilityState > ProjectDataManagement::VulnerabilityState::VulnerabilityState_CatastrophicKill) continue; if (stateList.at(i).originatorType == ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_Sanitation || stateList.at(i).originatorType == ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_MedicalTimeout) continue; if (tCurrent > youngestState.stateTime) continue; bool higherState = (stateList.at(i).vulnerabilityState > stateList.at(youngest).vulnerabilityState ) || (stateList.at(i).vulnerabilityState == stateList.at(youngest).vulnerabilityState && (stateList.at(i).vitality < stateList.at(youngest).vitality)); if ((tCurrent > tYoungest && (stateList.at(i).originatorType == ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_ObserverController || stateList.at(i).originatorType == ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_ExerciseControl)) || (tCurrent > tYoungest && higherState) || (tCurrent == tYoungest && higherState)) youngest = i; } if (youngest == 0) return youngestState; return stateList.at(youngest); } ParticipantManagement::SanitationResult proceduresDone(const std::vector &stateList) { // Empty List or 1 Entry ("CombatReady"): No Effect if (stateList.size() <= 1) return SanitationResult::NoEffect; // If that guy is killed: NoEffect StateInformation youngestReal = youngestRealStateInformation(stateList); if (youngestReal.vulnerabilityState == ProjectDataManagement::VulnerabilityState::VulnerabilityState_CatastrophicKill) return SanitationResult::NoEffect; SanitationResult ret = SanitationResult::Unhandled; for (size_t i = 1; i < stateList.size(); ++i) { // Better than "Unhandled" can only occur if this is done by Sanitation or O/C if (stateList.at(i).originatorType != ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_Sanitation && stateList.at(i).originatorType != ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_ObserverController ) continue; // Let's find the newest if (stateList.at(i).stateTime < youngestReal.stateTime) continue; // if (ret == SanitationResult::Unhandled ) //we have a sanitation so at least 1 ret = stateList.at(i).sanitationResult; if (stateList.at(i).sanitationResult == SanitationResult::Sufficient && ret != SanitationResult::Optimal ) ret = SanitationResult::Sufficient; if (stateList.at(i).sanitationResult == SanitationResult::Optimal) ret = SanitationResult::Optimal; } return ret; } } // namespace ParticipantManagement