diff --git a/src/blackcore/airspace_analyzer.cpp b/src/blackcore/airspace_analyzer.cpp index 48ef92b5c..7ce3430e2 100644 --- a/src/blackcore/airspace_analyzer.cpp +++ b/src/blackcore/airspace_analyzer.cpp @@ -7,7 +7,8 @@ * contained in the LICENSE file. */ -#include "airspace_analyzer.h" +#include "blackcore/airspace_analyzer.h" +#include "blackcore/blackcorefreefunctions.h" #include "blackmisc/logmessage.h" #include @@ -30,7 +31,7 @@ namespace BlackCore // all in new thread from here on m_timer.setObjectName(this->objectName().append(":m_timer")); - m_timer.start(5000); + m_timer.start(7500); bool c = connect(&m_timer, &QTimer::timeout, this, &CAirspaceAnalyzer::ps_timeout); Q_ASSERT(c); @@ -53,7 +54,8 @@ namespace BlackCore Q_ASSERT(c); Q_UNUSED(c); - this->start(); + // start in own thread + this->start(QThread::LowestPriority); } CAirspaceAircraftSnapshot CAirspaceAnalyzer::getLatestAirspaceAircraftSnapshot() const @@ -172,6 +174,9 @@ namespace BlackCore void CAirspaceAnalyzer::analyzeAirspace() { + Q_ASSERT_X(!isCurrentThreadApplicationThread(), Q_FUNC_INFO, "Expect to run in background thread"); + Q_ASSERT_X(!isApplicationThreadObjectThread(this), Q_FUNC_INFO, "Expect to run in background thread affinity"); + bool restricted; int maxAircraft; CLength maxRenderedDistance, maxRenderedBoundary; @@ -183,17 +188,24 @@ namespace BlackCore maxRenderedBoundary = this->m_simulatorMaxRenderedBoundary; } + //! \todo Analyzer: generate only when restricted? + + CSimulatedAircraftList aircraftInRange(getAircraftInRange()); // thread safe copy from provider CAirspaceAircraftSnapshot snapshot( - getAircraftInRange(), // thread safe copy + aircraftInRange, restricted, maxAircraft, maxRenderedDistance, maxRenderedBoundary ); // lock block { QWriteLocker l(&m_lockSnapshot); - snapshot.setRestrictionChanged(m_latestAircraftSnapshot); + bool wasValid = m_latestAircraftSnapshot.isValidSnapshot(); m_latestAircraftSnapshot = snapshot; + + if (!wasValid) { return; } // ignore the 1st snapshot + snapshot.setRestrictionChanged(m_latestAircraftSnapshot); } + emit airspaceAircraftSnapshot(snapshot); } diff --git a/src/blackcore/airspace_monitor.cpp b/src/blackcore/airspace_monitor.cpp index aa4bf4e24..3a9fb2c11 100644 --- a/src/blackcore/airspace_monitor.cpp +++ b/src/blackcore/airspace_monitor.cpp @@ -58,9 +58,12 @@ namespace BlackCore this->connect(this->m_vatsimBookingReader, &CVatsimBookingReader::dataRead, this, &CAirspaceMonitor::ps_receivedBookings); this->connect(this->m_vatsimDataFileReader, &CVatsimDataFileReader::dataRead, this, &CAirspaceMonitor::ps_receivedDataFile); + // Force snapshot in the main event loop + this->connect(this->m_analyzer, &CAirspaceAnalyzer::airspaceAircraftSnapshot, this, &CAirspaceMonitor::airspaceAircraftSnapshot, Qt::QueuedConnection); + // Analyzer - this->connect(this->m_analyzer, &CAirspaceAnalyzer::timeoutAircraft, this, &CAirspaceMonitor::ps_pilotDisconnected); - this->connect(this->m_analyzer, &CAirspaceAnalyzer::timeoutAtc, this, &CAirspaceMonitor::ps_atcControllerDisconnected); + this->connect(this->m_analyzer, &CAirspaceAnalyzer::timeoutAircraft, this, &CAirspaceMonitor::ps_pilotDisconnected, Qt::QueuedConnection); + this->connect(this->m_analyzer, &CAirspaceAnalyzer::timeoutAtc, this, &CAirspaceMonitor::ps_atcControllerDisconnected, Qt::QueuedConnection); } CSimulatedAircraftList CAirspaceMonitor::getAircraftInRange() const @@ -136,14 +139,18 @@ namespace BlackCore std::function aircraftSnapshotSlot ) { + // bind does not allow to define connection type + // so anything in its own thread will be sent with this thread affinity QMetaObject::Connection c1 = connect(this, &CAirspaceMonitor::addedAircraftSituation, situationSlot); - Q_ASSERT(c1); + Q_ASSERT_X(c1, Q_FUNC_INFO, "connect failed"); QMetaObject::Connection c2 = connect(this, &CAirspaceMonitor::addedAircraftParts, partsSlot); - Q_ASSERT(c2); + Q_ASSERT_X(c2, Q_FUNC_INFO, "connect failed"); QMetaObject::Connection c3 = connect(this, &CAirspaceMonitor::removedAircraft, removedAircraftSlot); - Q_ASSERT(c3); - QMetaObject::Connection c4 = this->connect(this->m_analyzer, &CAirspaceAnalyzer::airspaceAircraftSnapshot, aircraftSnapshotSlot); - Q_ASSERT(c4); + Q_ASSERT_X(c3, Q_FUNC_INFO, "connect failed"); + // trick is to use the Queued signal here + // analyzer (own thread) -> airspaceAircraftSnapshot -> AirspaceMonitor -> airspaceAircraftSnapshot queued in main thread + QMetaObject::Connection c4 = this->connect(this, &CAirspaceMonitor::airspaceAircraftSnapshot, aircraftSnapshotSlot); + Q_ASSERT_X(c4, Q_FUNC_INFO, "connect failed"); return QList({ c1, c2, c3, c4}); } @@ -600,7 +607,7 @@ namespace BlackCore void CAirspaceMonitor::ps_receivedBookings(const CAtcStationList &bookedStations) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); if (bookedStations.isEmpty()) { this->m_atcStationsBooked.clear(); @@ -620,7 +627,7 @@ namespace BlackCore void CAirspaceMonitor::ps_receivedDataFile() { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); for (auto client = this->m_otherClients.begin(); client != this->m_otherClients.end(); ++client) { if (client->hasSpecifiedVoiceCapabilities()) { continue; } // we already have voice caps @@ -667,7 +674,7 @@ namespace BlackCore void CAirspaceMonitor::ps_atcPositionUpdate(const CCallsign &callsign, const BlackMisc::PhysicalQuantities::CFrequency &frequency, const CCoordinateGeodetic &position, const BlackMisc::PhysicalQuantities::CLength &range) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); Q_ASSERT(CComSystem::isValidCivilAviationFrequency(frequency)); if (!this->m_connected) { return; } CAtcStationList stationsWithCallsign = this->m_atcStationsOnline.findByCallsign(callsign); @@ -718,7 +725,7 @@ namespace BlackCore void CAirspaceMonitor::ps_atcControllerDisconnected(const CCallsign &callsign) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); this->m_otherClients.removeByCallsign(callsign); if (this->m_atcStationsOnline.containsCallsign(callsign)) @@ -735,7 +742,7 @@ namespace BlackCore void CAirspaceMonitor::ps_atisReceived(const CCallsign &callsign, const CInformationMessage &atisMessage) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); if (!this->m_connected || callsign.isEmpty()) return; CPropertyIndexVariantMap vm(CAtcStation::IndexAtis, atisMessage.toCVariant()); int changedOnline = this->m_atcStationsOnline.applyIf(&CAtcStation::getCallsign, callsign, vm); @@ -749,7 +756,7 @@ namespace BlackCore void CAirspaceMonitor::ps_atisVoiceRoomReceived(const CCallsign &callsign, const QString &url) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); if (!this->m_connected) { return; } QString trimmedUrl = url.trimmed(); CPropertyIndexVariantMap vm({ CAtcStation::IndexVoiceRoom, CVoiceRoom::IndexUrl }, trimmedUrl); @@ -776,7 +783,7 @@ namespace BlackCore void CAirspaceMonitor::ps_atisLogoffTimeReceived(const CCallsign &callsign, const QString &zuluTime) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); if (!this->m_connected) { return; } if (zuluTime.length() == 4) { @@ -800,7 +807,7 @@ namespace BlackCore void CAirspaceMonitor::ps_icaoCodesReceived(const CCallsign &callsign, const CAircraftIcaoData &icaoData) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); Q_ASSERT(!callsign.isEmpty()); if (!this->m_connected) { return; } @@ -833,7 +840,7 @@ namespace BlackCore void CAirspaceMonitor::ps_aircraftUpdateReceived(const CAircraftSituation &situation, const CTransponder &transponder) { - Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), Q_FUNC_INFO, "Called in different thread"); + Q_ASSERT_X(BlackCore::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "Called in different thread"); if (!this->m_connected) { return; } CCallsign callsign(situation.getCallsign()); @@ -923,7 +930,7 @@ namespace BlackCore void CAirspaceMonitor::ps_aircraftInterimUpdateReceived(const CAircraftSituation &situation) { - Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), Q_FUNC_INFO, "Called in different thread"); + Q_ASSERT_X(BlackCore::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "Called in different thread"); if (!this->m_connected) { return; } CCallsign callsign(situation.getCallsign()); @@ -955,14 +962,16 @@ namespace BlackCore vm.addValue(CAircraft::IndexDistanceToOwnAircraft, distance); // here I expect always a changed value + { + QWriteLocker l(&m_lockAircraft); + this->m_aircraftInRange.applyIfCallsign(callsign, vm); + } emit this->changedAircraftInRange(); - QWriteLocker l(&m_lockAircraft); - this->m_aircraftInRange.applyIfCallsign(callsign, vm); } void CAirspaceMonitor::ps_pilotDisconnected(const CCallsign &callsign) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); // in case of inconsistencies I always remove here this->m_otherClients.removeByCallsign(callsign); @@ -989,7 +998,7 @@ namespace BlackCore void CAirspaceMonitor::ps_frequencyReceived(const CCallsign &callsign, const CFrequency &frequency) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); // update int changed; @@ -1003,7 +1012,7 @@ namespace BlackCore void CAirspaceMonitor::ps_aircraftConfigReceived(const BlackMisc::Aviation::CCallsign &callsign, const QJsonObject &jsonObject, bool isFull) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); CSimulatedAircraft simAircraft(getAircraftInRangeForCallsign(callsign)); @@ -1039,7 +1048,7 @@ namespace BlackCore void CAirspaceMonitor::ps_sendInterimPositions() { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); if (!this->m_connected || !m_sendInterimPositions) { return; } CSimulatedAircraftList aircrafts = m_aircraftInRange.findBy(&CSimulatedAircraft::fastPositionUpdates, true); m_network->sendInterimPositions(aircrafts.getCallsigns()); diff --git a/src/blackcore/airspace_monitor.h b/src/blackcore/airspace_monitor.h index c6566e927..d243eeec4 100644 --- a/src/blackcore/airspace_monitor.h +++ b/src/blackcore/airspace_monitor.h @@ -197,6 +197,9 @@ namespace BlackCore //! An aircraft disappeared void removedAircraft(const BlackMisc::Aviation::CCallsign &callsign); + //! \copydoc CAirspaceAnalyzer::airspaceAircraftSnapshot + void airspaceAircraftSnapshot(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &snapshot); + private: BlackMisc::Aviation::CAtcStationList m_atcStationsOnline; BlackMisc::Aviation::CAtcStationList m_atcStationsBooked; diff --git a/src/blackcore/blackcorefreefunctions.cpp b/src/blackcore/blackcorefreefunctions.cpp index 50544091d..fd54cc238 100644 --- a/src/blackcore/blackcorefreefunctions.cpp +++ b/src/blackcore/blackcorefreefunctions.cpp @@ -17,11 +17,25 @@ namespace BlackCore qRegisterMetaType(); } - bool isCurrentThreadCreatingThread(QObject *toBeTested) + bool isCurrentThreadObjectThread(QObject *toBeTested) { + Q_ASSERT_X(toBeTested, Q_FUNC_INFO, "missing QObject"); if (!toBeTested) { return false; } if (!toBeTested->thread()) { return false; } - return (QThread::currentThreadId() == toBeTested->thread()->currentThreadId()); + return (QThread::currentThread() == toBeTested->thread()); + } + + bool isApplicationThreadObjectThread(QObject *toBeTested) + { + Q_ASSERT_X(toBeTested, Q_FUNC_INFO, "missing QObject"); + if (!toBeTested) { return false; } + if (!toBeTested->thread()) { return false; } + return (QCoreApplication::instance()->thread() == toBeTested->thread()); + } + + bool isCurrentThreadApplicationThread() + { + return (QCoreApplication::instance()->thread() == QThread::currentThread()); } } // namespace diff --git a/src/blackcore/blackcorefreefunctions.h b/src/blackcore/blackcorefreefunctions.h index a108610f7..4339aac75 100644 --- a/src/blackcore/blackcorefreefunctions.h +++ b/src/blackcore/blackcorefreefunctions.h @@ -14,9 +14,17 @@ namespace BlackCore //! Register all relevant metadata in BlackCore BLACKCORE_EXPORT void registerMetadata(); - //! Is the current thread the one created the object + //! Is the current thread the QObject's thread? //! \remarks can be used as ASSERT check for threaded objects - BLACKCORE_EXPORT bool isCurrentThreadCreatingThread(QObject *toBeTested); + BLACKCORE_EXPORT bool isCurrentThreadObjectThread(QObject *toBeTested); + + //! Is the application thread the QObject's thread? + //! \remarks can be used as ASSERT check for threaded objects + BLACKCORE_EXPORT bool isApplicationThreadObjectThread(QObject *toBeTested); + + //! Is the current thread the Application thread? + //! \remarks can be used as ASSERT check for threaded objects + BLACKCORE_EXPORT bool isCurrentThreadApplicationThread(); } // BlackCore diff --git a/src/blackcore/simulator.h b/src/blackcore/simulator.h index df9c4d71b..69a8a6126 100644 --- a/src/blackcore/simulator.h +++ b/src/blackcore/simulator.h @@ -214,10 +214,10 @@ namespace BlackCore virtual bool physicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) = 0; //! Remove remote aircraft from simulator - virtual bool physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns) = 0; + virtual int physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns) = 0; //! Remove all remote aircraft - virtual void physicallyRemoveAllRemoteAircraft() = 0; + virtual int physicallyRemoveAllRemoteAircraft() = 0; //! Emit the combined status //! \sa simulatorStatusChanged; diff --git a/src/blackcore/simulator_common.cpp b/src/blackcore/simulator_common.cpp index 6e45f1405..71155fb53 100644 --- a/src/blackcore/simulator_common.cpp +++ b/src/blackcore/simulator_common.cpp @@ -38,7 +38,7 @@ namespace BlackCore std::bind(&CSimulatorCommon::ps_remoteProviderAddAircraftSituation, this, std::placeholders::_1), std::bind(&CSimulatorCommon::ps_remoteProviderAddAircraftParts, this, std::placeholders::_1), std::bind(&CSimulatorCommon::ps_remoteProviderRemovedAircraft, this, std::placeholders::_1), - std::bind(static_cast(&CSimulatorCommon::ps_recalculateRenderedAircraft), this, std::placeholders::_1)); + std::bind(&CSimulatorCommon::ps_recalculateRenderedAircraft, this, std::placeholders::_1)); // timer this->m_oneSecondTimer.setObjectName(this->objectName().append(":m_oneSecondTimer")); @@ -97,7 +97,7 @@ namespace BlackCore for (const CSimulatedAircraft &aircraft : m_highlightedAircraft) { // get the current state for this aircraft - // it might has been removed in the mean time + // it might has been removed in the meantime const CCallsign cs(aircraft.getCallsign()); resetAircraftFromBacked(cs); } @@ -124,19 +124,26 @@ namespace BlackCore } } - void CSimulatorCommon::setInitialAircraftSituationAndParts(CSimulatedAircraft &aircraft) const + bool CSimulatorCommon::setInitialAircraftSituation(CSimulatedAircraft &aircraft) const { - if (!this->m_interpolator) { return; } - + if (!this->m_interpolator) { return false; } const CCallsign callsign(aircraft.getCallsign()); - if (this->remoteAircraftSituationsCount(callsign) < 1) { return; } + Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign"); // with an interpolator the interpolated situation is used - // to avoid position jittering + // to avoid position jittering when displayed qint64 time = QDateTime::currentMSecsSinceEpoch(); IInterpolator::InterpolationStatus interpolationStatus; CAircraftSituation as(m_interpolator->getInterpolatedSituation(callsign, time, aircraft.isVtol(), interpolationStatus)); - if (interpolationStatus.interpolationSucceeded) { aircraft.setSituation(as); } + if (interpolationStatus.interpolationSucceeded) + { + aircraft.setSituation(as); + return true; + } + else + { + return false; + } } int CSimulatorCommon::getMaxRenderedAircraft() const @@ -268,14 +275,14 @@ namespace BlackCore emit renderRestrictionsChanged(false, getMaxRenderedAircraft(), getMaxRenderedDistance(), getRenderedDistanceBoundary()); } - bool CSimulatorCommon::physicallyRemoveMultipleRemoteAircraft(const CCallsignSet &callsigns) + int CSimulatorCommon::physicallyRemoveMultipleRemoteAircraft(const CCallsignSet &callsigns) { int removed = 0; for (const CCallsign &callsign : callsigns) { if (physicallyRemoveRemoteAircraft(callsign)) { removed++; } } - return removed > 0; + return removed; } void CSimulatorCommon::ps_oneSecondTimer() @@ -283,28 +290,29 @@ namespace BlackCore blinkHighlightedAircraft(); } - void CSimulatorCommon::ps_recalculateRenderedAircraft() - { - this->ps_recalculateRenderedAircraft(getLatestAirspaceAircraftSnapshot()); - } - void CSimulatorCommon::ps_recalculateRenderedAircraft(const CAirspaceAircraftSnapshot &snapshot) { - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); - if (!snapshot.isValidSnapshot()) { return;} // for unrestricted values all add/remove actions are directly linked // when changing back from restricted->unrestricted an one time update is required if (!snapshot.isRestricted() && !snapshot.isRestrictionChanged()) { return; } + Q_ASSERT_X(BlackCore::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "Needs to run in object thread"); + Q_ASSERT_X(snapshot.generatingThreadName() != QThread::currentThread(), Q_FUNC_INFO, "Expect snapshot from background thread"); + // restricted snapshot values? + bool changed = false; if (snapshot.isRenderingEnabled()) { - CCallsignSet callsignsInSimulator(physicallyRenderedAircraft()); + CCallsignSet callsignsInSimulator(physicallyRenderedAircraft()); // state in simulator CCallsignSet callsignsToBeRemoved(callsignsInSimulator.difference(snapshot.getEnabledAircraftCallsignsByDistance())); CCallsignSet callsignsToBeAdded(snapshot.getEnabledAircraftCallsignsByDistance().difference(callsignsInSimulator)); - this->physicallyRemoveMultipleRemoteAircraft(callsignsToBeRemoved); + if (!callsignsToBeRemoved.isEmpty()) + { + int r = this->physicallyRemoveMultipleRemoteAircraft(callsignsToBeRemoved); + changed = r > 0; + } if (!callsignsToBeAdded.isEmpty()) { @@ -312,18 +320,23 @@ namespace BlackCore for (const CSimulatedAircraft &aircraft : aircraftToBeAdded) { Q_ASSERT_X(aircraft.isEnabled(), Q_FUNC_INFO, "Disabled aircraft detected as to be added"); - this->physicallyAddRemoteAircraft(aircraft); + bool a = this->physicallyAddRemoteAircraft(aircraft); + changed = changed || a; } } } else { - this->physicallyRemoveAllRemoteAircraft(); + // no rendering at all, we remove everything + int r = this->physicallyRemoveAllRemoteAircraft(); + changed = r > 0; } // we handled snapshot - emit airspaceSnapshotHandled(); - + if (changed) + { + emit airspaceSnapshotHandled(); + } } void CSimulatorCommon::ps_remoteProviderAddAircraftSituation(const CAircraftSituation &situation) diff --git a/src/blackcore/simulator_common.h b/src/blackcore/simulator_common.h index 598fb88ca..926c7b9dd 100644 --- a/src/blackcore/simulator_common.h +++ b/src/blackcore/simulator_common.h @@ -93,15 +93,12 @@ namespace BlackCore virtual void deleteAllRenderingRestrictions() override; //! \copydoc IContextSimulator::physicallyRemoveRemoteAircraft - virtual bool physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns) override; + virtual int physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns) override; protected slots: //! Slow timer used to highlight aircraft, can be used for other things too virtual void ps_oneSecondTimer(); - //! Recalculate the rendered aircraft - virtual void ps_recalculateRenderedAircraft(); - //! Recalculate the rendered aircraft virtual void ps_recalculateRenderedAircraft(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &snapshot); @@ -130,11 +127,11 @@ namespace BlackCore //! Blink the highlighted aircraft void blinkHighlightedAircraft(); - //! Restore aircraft from backedn data + //! Restore aircraft from backend data void resetAircraftFromBacked(const BlackMisc::Aviation::CCallsign &callsign); - //! Override parts and situation from current interpolator values, if any! - void setInitialAircraftSituationAndParts(BlackMisc::Simulation::CSimulatedAircraft &aircraft) const; + //! Override situation from current interpolator values, if any! + bool setInitialAircraftSituation(BlackMisc::Simulation::CSimulatedAircraft &aircraft) const; bool m_debugMessages = false; //!< Display debug messages bool m_blinkCycle = false; //!< use for highlighting diff --git a/src/blackmisc/simulation/airspaceaircraftsnapshot.cpp b/src/blackmisc/simulation/airspaceaircraftsnapshot.cpp index b9a77e27d..093fc790a 100644 --- a/src/blackmisc/simulation/airspaceaircraftsnapshot.cpp +++ b/src/blackmisc/simulation/airspaceaircraftsnapshot.cpp @@ -23,7 +23,8 @@ namespace BlackMisc const CSimulatedAircraftList &allAircraft, bool restricted, int maxAircraft, const CLength &maxRenderedDistance, const CLength &maxRenderedBoundary) : m_timestampMsSinceEpoch(QDateTime::currentMSecsSinceEpoch()), - m_restricted(restricted) + m_restricted(restricted), + m_threadName(QThread::currentThread()->objectName()) { m_renderingEnabled = !restricted || ( maxAircraft > 0 && @@ -38,45 +39,46 @@ namespace BlackMisc m_aircraftCallsignsByDistance = aircraft.getCallsigns(); m_vtolAircraftCallsignsByDistance = vtolAircraft.getCallsigns(); + // no restrictions, just find by attributes if (!restricted) { m_enabledAircraftCallsignsByDistance = aircraft.findByEnabled(true).getCallsigns(); m_disabledAircraftCallsignsByDistance = aircraft.findByEnabled(false).getCallsigns(); m_enabledVtolAircraftCallsignsByDistance = vtolAircraft.findByEnabled(true).getCallsigns(); + return; } - else - { - // if no rendering all aircraft are disabled - if (!m_renderingEnabled) - { - m_disabledAircraftCallsignsByDistance = aircraft.getCallsigns(); - return; - } - int count = 0; - for (const CSimulatedAircraft ¤tAircraft : aircraft) + // no rendering, this means all aircraft are disabled + if (!m_renderingEnabled) + { + m_disabledAircraftCallsignsByDistance = aircraft.getCallsigns(); + return; + } + + // restricted + int count = 0; // when max. aircraft reached? + for (const CSimulatedAircraft ¤tAircraft : aircraft) + { + CCallsign cs(currentAircraft.getCallsign()); + if (currentAircraft.isEnabled()) { - CCallsign cs(currentAircraft.getCallsign()); - if (currentAircraft.isEnabled()) - { - CLength distance(currentAircraft.getDistanceToOwnAircraft()); - if (count >= maxAircraft || - (!maxRenderedDistance.isNull() && distance >= maxRenderedBoundary) || - (!maxRenderedBoundary.isNull() && distance >= maxRenderedBoundary)) - { - m_disabledAircraftCallsignsByDistance.push_back(cs); - } - else - { - count++; - m_enabledAircraftCallsignsByDistance.push_back(cs); - if (currentAircraft.isVtol()) { m_enabledVtolAircraftCallsignsByDistance.push_back(cs); } - } - } - else + CLength distance(currentAircraft.getDistanceToOwnAircraft()); + if (count >= maxAircraft || + (!maxRenderedDistance.isNull() && distance >= maxRenderedBoundary) || + (!maxRenderedBoundary.isNull() && distance >= maxRenderedBoundary)) { m_disabledAircraftCallsignsByDistance.push_back(cs); } + else + { + count++; + m_enabledAircraftCallsignsByDistance.push_back(cs); + if (currentAircraft.isVtol()) { m_enabledVtolAircraftCallsignsByDistance.push_back(cs); } + } + } + else + { + m_disabledAircraftCallsignsByDistance.push_back(cs); } } } diff --git a/src/blackmisc/simulation/airspaceaircraftsnapshot.h b/src/blackmisc/simulation/airspaceaircraftsnapshot.h index 3916fd604..d626c50ab 100644 --- a/src/blackmisc/simulation/airspaceaircraftsnapshot.h +++ b/src/blackmisc/simulation/airspaceaircraftsnapshot.h @@ -83,12 +83,16 @@ namespace BlackMisc //! \copydoc CValueObject::convertToQString QString convertToQString(bool i18n = false) const; + //! Generating thread name + const QString &generatingThreadName() const { return m_threadName; } + private: BLACK_ENABLE_TUPLE_CONVERSION(CAirspaceAircraftSnapshot) qint64 m_timestampMsSinceEpoch = -1; bool m_restricted = false; bool m_restrictionChanged = false; bool m_renderingEnabled = true; + QString m_threadName; //!< generating thread name for debugging purposes // remark closest aircraft always first BlackMisc::Aviation::CCallsignSet m_aircraftCallsignsByDistance; diff --git a/src/blackmisc/simulation/remoteaircraftprovider.h b/src/blackmisc/simulation/remoteaircraftprovider.h index 6ab931eb1..783293841 100644 --- a/src/blackmisc/simulation/remoteaircraftprovider.h +++ b/src/blackmisc/simulation/remoteaircraftprovider.h @@ -108,6 +108,7 @@ namespace BlackMisc std::function removedAircraftSlot, std::function aircraftSnapshot ) = 0; + }; //! Class which can be directly used to access an \sa IRemoteAircraftProvider object @@ -165,6 +166,6 @@ namespace BlackMisc } // namespace } // namespace -Q_DECLARE_INTERFACE(BlackMisc::Simulation::IRemoteAircraftProvider, "IRemoteAircraftProvider") +Q_DECLARE_INTERFACE(BlackMisc::Simulation::IRemoteAircraftProvider, "BlackMisc::Simulation::IRemoteAircraftProvider:IRemoteAircraftProvider") #endif // guard diff --git a/src/blackmisc/timestampobjectlist.cpp b/src/blackmisc/timestampobjectlist.cpp index 791e1d5e0..ba548c275 100644 --- a/src/blackmisc/timestampobjectlist.cpp +++ b/src/blackmisc/timestampobjectlist.cpp @@ -75,6 +75,7 @@ namespace BlackMisc template QList ITimestampObjectList::splitByTime(qint64 msSinceEpoch, bool alreadySortedLatestFirst) const { + // fixme: Split by time is one of the most frequently called functions in interpolator, so any performance improvement here counts CONTAINER newer(this->container()); if (!alreadySortedLatestFirst) { newer.sortLatestFirst(); } CONTAINER older; @@ -82,7 +83,6 @@ namespace BlackMisc { if (it->isOlderThan(msSinceEpoch)) { - // better "move", ?? std::make_move_iterator older.insert(CRange(it, newer.end())); newer.erase(it, newer.end()); break; diff --git a/src/plugins/simulator/fs9/simulator_fs9.cpp b/src/plugins/simulator/fs9/simulator_fs9.cpp index 7f681a4bd..7a9c6b044 100644 --- a/src/plugins/simulator/fs9/simulator_fs9.cpp +++ b/src/plugins/simulator/fs9/simulator_fs9.cpp @@ -133,13 +133,17 @@ namespace BlackSimPlugin return true; } - void CSimulatorFs9::physicallyRemoveAllRemoteAircraft() + int CSimulatorFs9::physicallyRemoveAllRemoteAircraft() { + if (this->m_hashFs9Clients.isEmpty()) { return 0; } QList callsigns(this->m_hashFs9Clients.keys()); + int r = 0; for (const CCallsign &cs : callsigns) { - physicallyRemoveRemoteAircraft(cs); + if (physicallyRemoveRemoteAircraft(cs)) { r++; } } + return r; + } CCallsignSet CSimulatorFs9::physicallyRenderedAircraft() const diff --git a/src/plugins/simulator/fs9/simulator_fs9.h b/src/plugins/simulator/fs9/simulator_fs9.h index 68b4a6aa0..d9378cdec 100644 --- a/src/plugins/simulator/fs9/simulator_fs9.h +++ b/src/plugins/simulator/fs9/simulator_fs9.h @@ -64,7 +64,7 @@ namespace BlackSimPlugin virtual bool physicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override; //! \copydoc BlackCore::ISimulator::physicallyRemoveAllRemoteAircraft - virtual void physicallyRemoveAllRemoteAircraft() override; + virtual int physicallyRemoveAllRemoteAircraft() override; //! \copydoc ISimulator::physicallyRenderedAircraft virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override; diff --git a/src/plugins/simulator/fscommon/simulator_fscommon.cpp b/src/plugins/simulator/fscommon/simulator_fscommon.cpp index 053d6ade2..ac687d99e 100644 --- a/src/plugins/simulator/fscommon/simulator_fscommon.cpp +++ b/src/plugins/simulator/fscommon/simulator_fscommon.cpp @@ -31,7 +31,7 @@ namespace BlackSimPlugin IRemoteAircraftProvider *renderedAircraftProvider, QObject *parent) : CSimulatorCommon(info, ownAircraftProvider, renderedAircraftProvider, parent), - m_fsuipc(new FsCommon::CFsuipc()) + m_fsuipc(new CFsuipc()) { // hack to init mapper CAircraftMapper *mapper = mapperInstance(); diff --git a/src/plugins/simulator/fsx/simulator_fsx.cpp b/src/plugins/simulator/fsx/simulator_fsx.cpp index 092709469..ceffa175a 100644 --- a/src/plugins/simulator/fsx/simulator_fsx.cpp +++ b/src/plugins/simulator/fsx/simulator_fsx.cpp @@ -139,7 +139,7 @@ namespace BlackSimPlugin bool CSimulatorFsx::physicallyAddRemoteAircraft(const Simulation::CSimulatedAircraft &newRemoteAircraft) { CCallsign callsign(newRemoteAircraft.getCallsign()); - Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), Q_FUNC_INFO, "thread"); + Q_ASSERT_X(BlackCore::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "thread"); Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign"); if (callsign.isEmpty()) { return false; } @@ -151,38 +151,41 @@ namespace BlackSimPlugin CLogMessage(this).warning("Have to remove aircraft %1 before I can add it") << callsign; } - CSimulatedAircraft newRemoteAircraftCopy(newRemoteAircraft); // copy which can be modified - this->setInitialAircraftSituationAndParts(newRemoteAircraftCopy); // set interpolated data/parts if available - SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxInitPosition(newRemoteAircraftCopy.getSituation()); - CSimConnectObject simObj(callsign, m_nextObjID, 0, newRemoteAircraft.isVtol()); ++m_nextObjID; // matched models - CAircraftModel aircraftModel = modelMatching(newRemoteAircraftCopy); + CAircraftModel aircraftModel = modelMatching(newRemoteAircraft); Q_ASSERT_X(newRemoteAircraft.getCallsign() == aircraftModel.getCallsign(), Q_FUNC_INFO, "mismatching callsigns"); + this->updateAircraftModel(callsign, aircraftModel, simulatorOriginator()); - this->updateAircraftRendered(callsign, true, simulatorOriginator()); CSimulatedAircraft aircraftAfterModelApplied(getAircraftInRangeForCallsign(newRemoteAircraft.getCallsign())); - aircraftAfterModelApplied.setRendered(true); - emit modelMatchingCompleted(aircraftAfterModelApplied); // create AI + bool rendered = false; if (isConnected()) { - //! \todo FSX driver if exists, recreate (new model?, new ICAO code) + // initial position + this->setInitialAircraftSituation(aircraftAfterModelApplied); // set interpolated data/parts if available + + SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxInitPosition(aircraftAfterModelApplied.getSituation()); QByteArray m = aircraftModel.getModelString().toLocal8Bit(); HRESULT hr = SimConnect_AICreateNonATCAircraft(m_hSimConnect, m.constData(), qPrintable(callsign.toQString().left(12)), initialPosition, static_cast(simObj.getRequestId())); if (hr != S_OK) { CLogMessage(this).error("SimConnect, can not create AI traffic"); } m_simConnectObjects.insert(callsign, simObj); CLogMessage(this).info("FSX: Added aircraft %1") << callsign.toQString(); - return true; + rendered = true; } else { CLogMessage(this).warning("FSX: Not connected, not added aircraft %1") << callsign.toQString(); - return false; } + + aircraftAfterModelApplied.setRendered(rendered); + this->updateAircraftRendered(callsign, rendered, simulatorOriginator()); + emit modelMatchingCompleted(aircraftAfterModelApplied); + + return rendered; } bool CSimulatorFsx::updateOwnSimulatorCockpit(const CAircraft &ownAircraft, const QString &originator) @@ -531,18 +534,21 @@ namespace BlackSimPlugin bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CCallsign &callsign) { // only remove from sim - Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this)); + Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this)); if (!m_simConnectObjects.contains(callsign)) { return false; } return physicallyRemoveRemoteAircraft(m_simConnectObjects.value(callsign)); } - void CSimulatorFsx::physicallyRemoveAllRemoteAircraft() + int CSimulatorFsx::physicallyRemoveAllRemoteAircraft() { + if (m_simConnectObjects.isEmpty()) { return 0; } QList callsigns(m_simConnectObjects.keys()); + int r = 0; for (const CCallsign &cs : callsigns) { - physicallyRemoveRemoteAircraft(cs); + if (physicallyRemoveRemoteAircraft(cs)) { r++; } } + return r; } bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CSimConnectObject &simObject) @@ -637,7 +643,7 @@ namespace BlackSimPlugin { static_assert(sizeof(DataDefinitionRemoteAircraftParts) == 120, "DataDefinitionRemoteAircraftParts has an incorrect size."); Q_ASSERT_X(this->m_interpolator, Q_FUNC_INFO, "missing interpolator"); - Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), Q_FUNC_INFO, "thread"); + Q_ASSERT_X(BlackCore::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "thread"); // nothing to do, reset request id and exit if (this->isPaused() && this->m_pausedSimFreezesInterpolation) { return; } // no interpolation while paused diff --git a/src/plugins/simulator/fsx/simulator_fsx.h b/src/plugins/simulator/fsx/simulator_fsx.h index d1c86cb83..c560dca57 100644 --- a/src/plugins/simulator/fsx/simulator_fsx.h +++ b/src/plugins/simulator/fsx/simulator_fsx.h @@ -102,7 +102,7 @@ namespace BlackSimPlugin virtual bool physicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override; //! \copydoc BlackCore::ISimulator::physicallyRemoveAllRemoteAircraft - virtual void physicallyRemoveAllRemoteAircraft() override; + virtual int physicallyRemoveAllRemoteAircraft() override; //! \copydoc ISimulator::updateOwnCockpit virtual bool updateOwnSimulatorCockpit(const BlackMisc::Aviation::CAircraft &ownAircraft, const QString &originator) override; diff --git a/src/plugins/simulator/xplane/simulator_xplane.cpp b/src/plugins/simulator/xplane/simulator_xplane.cpp index 1ec25b43d..bd0fd1bb8 100644 --- a/src/plugins/simulator/xplane/simulator_xplane.cpp +++ b/src/plugins/simulator/xplane/simulator_xplane.cpp @@ -393,11 +393,14 @@ namespace BlackSimPlugin return true; } - void CSimulatorXPlane::physicallyRemoveAllRemoteAircraft() + int CSimulatorXPlane::physicallyRemoveAllRemoteAircraft() { + //! \todo XP driver obtain number of removed aircraft + int r = getAircraftInRangeCount(); m_traffic->removeAllPlanes(); updateMarkAllAsNotRendered(simulatorOriginator()); CLogMessage(this).info("XP: Removed all aircraft"); + return r; } CCallsignSet CSimulatorXPlane::physicallyRenderedAircraft() const diff --git a/src/plugins/simulator/xplane/simulator_xplane.h b/src/plugins/simulator/xplane/simulator_xplane.h index 9cf119dec..3aef4c861 100644 --- a/src/plugins/simulator/xplane/simulator_xplane.h +++ b/src/plugins/simulator/xplane/simulator_xplane.h @@ -60,7 +60,7 @@ namespace BlackSimPlugin virtual bool physicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override; //! \copydoc BlackCore::ISimulator::physicallyRemoveAllRemoteAircraft - virtual void physicallyRemoveAllRemoteAircraft() override; + virtual int physicallyRemoveAllRemoteAircraft() override; //! \copydoc ISimulator::physicallyRenderedAircraft virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override;