mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 23:05:36 +08:00
refs #395, improvements for snapshot / restricted aircraft handling
* fixed isCurrentThreadCreatingThread and renamed to isCurrentThreadObjectThread (this check was never working), added 2 more thread checks * changed remove aircraft function to return number of returned aircraft (like with the containers this allows to avoid unnecessary signals) * removed unused function ps_recalculateRenderedAircraft() / SimulatorCommon * using Queued airspaceAircraftSnapshot signal for binding (functor connect does not provide connection type) * extened ASSERTs to check threads * simulator: initial situation function with return value (success?) * simulator: avoid unneccessary copy and provide correct rendered flag in add aircraft function
This commit is contained in:
@@ -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 <QDateTime>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<void(const CAirspaceAircraftSnapshot &)> 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<QMetaObject::Connection>({ 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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -17,11 +17,25 @@ namespace BlackCore
|
||||
qRegisterMetaType<BlackCore::INetwork::ConnectionStatus>();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<void(CSimulatorCommon::*)(const CAirspaceAircraftSnapshot &)>(&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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace BlackMisc
|
||||
std::function<void(const BlackMisc::Aviation::CCallsign &)> removedAircraftSlot,
|
||||
std::function<void(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &)> 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
|
||||
|
||||
@@ -75,6 +75,7 @@ namespace BlackMisc
|
||||
template <class OBJ, class CONTAINER>
|
||||
QList<CONTAINER> ITimestampObjectList<OBJ, CONTAINER>::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<typename CONTAINER::iterator>(it, newer.end()));
|
||||
newer.erase(it, newer.end());
|
||||
break;
|
||||
|
||||
@@ -133,13 +133,17 @@ namespace BlackSimPlugin
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSimulatorFs9::physicallyRemoveAllRemoteAircraft()
|
||||
int CSimulatorFs9::physicallyRemoveAllRemoteAircraft()
|
||||
{
|
||||
if (this->m_hashFs9Clients.isEmpty()) { return 0; }
|
||||
QList<CCallsign> 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<SIMCONNECT_DATA_REQUEST_ID>(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<CCallsign> 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user