From 190e2c37575b343b43fb493618c45d1ad800652e Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Thu, 19 Feb 2015 02:14:20 +0100 Subject: [PATCH] refs #386, performance issues * keep split per callsign map in IInterpolator (so it is available for all interpolators) * added signals to provider to add split situations / callsigns * adjustments to airspace / context for those signals * thread safe access to those from interpolator * renamed from rendered to remote aircraft as discussed * adjust samples * removed no longer required functions in timestampobjectlist --- src/blackcore/airspace_monitor.h | 9 +- src/blackcore/interpolator.cpp | 63 ++++++---- src/blackcore/interpolator.h | 35 ++++-- src/blackcore/interpolator_linear.cpp | 109 ++++++++++++------ src/blackcore/interpolator_linear.h | 6 +- .../simdirectaccessremoteaircraft.h | 8 +- src/plugins/simulator/fs9/fs9_client.cpp | 2 +- src/plugins/simulator/fsx/simulator_fsx.cpp | 102 +++++++++++----- 8 files changed, 224 insertions(+), 110 deletions(-) diff --git a/src/blackcore/airspace_monitor.h b/src/blackcore/airspace_monitor.h index 86f6c48ed..062bb62d0 100644 --- a/src/blackcore/airspace_monitor.h +++ b/src/blackcore/airspace_monitor.h @@ -126,16 +126,16 @@ namespace BlackCore signals: - //--- signals for the provider, work locally only (not in DBus + //--- signals for the provider, work locally only (not in DBus) //! \copydoc IRemoteAircraftProviderReadOnly::addedRemoteAircraftSituation - void addedRemoteAircraftSituation(const BlackMisc::Aviation::CAircraftSituation &situation) override; + void addedRemoteAircraftSituation(const BlackMisc::Aviation::CAircraftSituation &situation); //! \copydoc IRemoteAircraftProviderReadOnly::addedRemoteAircraftPart - void addedRemoteAircraftParts(const BlackMisc::Aviation::CAircraftParts &parts) override; + void addedRemoteAircraftParts(const BlackMisc::Aviation::CAircraftParts &parts); //! \copydoc IRemoteAircraftProviderReadOnly::removedAircraft - void removedAircraft(const BlackMisc::Aviation::CCallsign &callsign) override; + void removedRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign); //! Online ATC stations were changed void changedAtcStationsOnline(); @@ -172,6 +172,7 @@ namespace BlackCore CVatsimDataFileReader *m_vatsimDataFileReader = nullptr; CAirspaceWatchdog m_atcWatchdog; CAirspaceWatchdog m_aircraftWatchdog; + bool m_serverSupportsNameQuery = false; //!< not all servers support name query // TODO FIXME (MS) should be in INetwork void sendFsipiCustomPacket(const BlackMisc::Aviation::CCallsign &recipientCallsign) const; diff --git a/src/blackcore/interpolator.cpp b/src/blackcore/interpolator.cpp index 899a319e3..1ab5f8d89 100644 --- a/src/blackcore/interpolator.cpp +++ b/src/blackcore/interpolator.cpp @@ -29,7 +29,7 @@ namespace BlackCore bool c = provider->connectRemoteAircraftProviderSignals( std::bind(&IInterpolator::ps_onAddedAircraftSituation, this, std::placeholders::_1), std::bind(&IInterpolator::ps_onAddedAircraftParts, this, std::placeholders::_1), - std::bind(&IInterpolator::ps_onRemoveAircraft, this, std::placeholders::_1) + std::bind(&IInterpolator::ps_onRemovedAircraft, this, std::placeholders::_1) ); Q_ASSERT(c); Q_UNUSED(c); @@ -63,18 +63,19 @@ namespace BlackCore return partsList.latestValue(); } - void IInterpolator::requestSituationsCalculationsForAllCallsigns(int requestId) + void IInterpolator::syncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch) { QReadLocker l(&m_situationsLock); Q_ASSERT(requestId >= 0); - const QHash situationsCopy = m_situationsByCallsign; + const QHash situationsCopy(m_situationsByCallsign); l.unlock(); CAircraftSituationList latestInterpolations; + if (currentTimeMsSinceEpoch < 0) { currentTimeMsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); } for (const CCallsign &cs : situationsCopy.keys()) { - bool ok; - CAircraftSituation situation = getCurrentInterpolatedSituation(situationsCopy, cs, &ok); + bool ok = false; + CAircraftSituation situation = getCurrentInterpolatedSituation(situationsCopy, cs, currentTimeMsSinceEpoch, &ok); if (ok) { latestInterpolations.push_back(situation); @@ -92,15 +93,33 @@ namespace BlackCore m_requestedInterpolations.erase(--m_requestedInterpolations.end()); } m_requestedInterpolations.insert(requestId, latestInterpolations); // new to old + if (m_withDebugMsg) + { + CLogMessage(this).debug() << "Added request" << requestId << "with" << latestInterpolations.size() << "interpolation(s)"; + } + } + void IInterpolator::asyncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch) + { + Q_ASSERT(requestId >= 0); + QMetaObject::invokeMethod(this, "syncRequestSituationsCalculationsForAllCallsigns", + Qt::QueuedConnection, Q_ARG(int, requestId), Q_ARG(qint64, currentTimeMsSinceEpoch)); } QHash IInterpolator::getSituationsByCallsign() const { - QReadLocker l(&m_requestedInterpolationsLock); + QReadLocker l(&m_situationsLock); return m_situationsByCallsign; } + CAircraftSituationList IInterpolator::getSituationsForCallsign(const CCallsign &callsign) const + { + QReadLocker l(&m_situationsLock); + static const CAircraftSituationList empty; + if (!m_situationsByCallsign.contains(callsign)) { return empty; } + return m_situationsByCallsign[callsign]; + } + int IInterpolator::latestFinishedRequestId() const { QReadLocker l(&m_requestedInterpolationsLock); @@ -132,41 +151,37 @@ namespace BlackCore void IInterpolator::ps_onAddedAircraftSituation(const CAircraftSituation &situation) { QWriteLocker lock(&m_situationsLock); - Q_ASSERT(!situation.getCallsign().isEmpty()); - if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << situation; } + const CCallsign callsign(situation.getCallsign()); + Q_ASSERT(!callsign.isEmpty()); + if (callsign.isEmpty()) { return; } + if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << situation.getCallsign() << situation.getMSecsSinceEpoch(); } // list from new to old - CAircraftSituationList &l = this->m_situationsByCallsign[situation.getCallsign()]; - if (l.size() >= MaxSituationsPerCallsign - 1) - { - l.truncate(MaxSituationsPerCallsign - 1); - } - l.insert(situation); + CAircraftSituationList &l = this->m_situationsByCallsign[callsign]; + l.insertTimestampObject(situation, MaxSituationsPerCallsign); } void IInterpolator::ps_onAddedAircraftParts(const CAircraftParts &parts) { QWriteLocker lock(&m_partsLock); - Q_ASSERT(!parts.getCallsign().isEmpty()); - if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << parts; } + const CCallsign callsign(parts.getCallsign()); + Q_ASSERT(!callsign.isEmpty()); + if (callsign.isEmpty()) { return; } + if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << parts.getCallsign() << parts.getMSecsSinceEpoch(); } // list from new to old - CAircraftPartsList &l = this->m_partsByCallsign[parts.getCallsign()]; - if (l.size() >= MaxPartsPerCallsign - 1) - { - l.truncate(MaxPartsPerCallsign - 1); - } - l.insert(parts); + CAircraftPartsList &l = this->m_partsByCallsign[callsign]; + l.insertTimestampObject(parts, MaxPartsPerCallsign); } - void IInterpolator::ps_onRemoveAircraft(const CCallsign &callsign) + void IInterpolator::ps_onRemovedAircraft(const CCallsign &callsign) { QWriteLocker ls(&m_situationsLock); QWriteLocker lp(&m_partsLock); Q_ASSERT(!callsign.isEmpty()); + if (callsign.isEmpty()) { return; } if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << callsign; } - if (callsign.isEmpty()) { return; } this->m_partsByCallsign.remove(callsign); this->m_situationsByCallsign.remove(callsign); } diff --git a/src/blackcore/interpolator.h b/src/blackcore/interpolator.h index 84e601308..0c81abebc 100644 --- a/src/blackcore/interpolator.h +++ b/src/blackcore/interpolator.h @@ -32,28 +32,30 @@ namespace BlackCore //! Virtual destructor virtual ~IInterpolator() {} + //! Log category + static QString getMessageCategory() { return "swift.iinterpolator"; } + //! Has situations? - //! \deprecated Try no to use, it would be more efficient to directly getting the values and decide then + //! \deprecated Try not to use, it would be more efficient to directly getting the values and decide then //! \threadsafe virtual bool hasEnoughAircraftSituations(const BlackMisc::Aviation::CCallsign &callsign) const; //! Current interpolated situation //! \threadsafe - virtual BlackMisc::Aviation::CAircraftSituation getCurrentInterpolatedSituation(const QHash &allSituations, const BlackMisc::Aviation::CCallsign &callsign, bool *ok = nullptr) const = 0; + virtual BlackMisc::Aviation::CAircraftSituation getCurrentInterpolatedSituation(const QHash &allSituations, const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc = -1, bool *ok = nullptr) const = 0; //! Latest parts before time - offset //! \threadsafe BlackMisc::Aviation::CAircraftParts getLatestPartsBeforeOffset(const BlackMisc::Aviation::CCallsign &callsign, qint64 timeOffset = TimeOffsetMs, bool *ok = nullptr) const; - //! Do a complete calculation for all know callsigns in background. - //! Only use positive numbers. - //! \threadsafe - void requestSituationsCalculationsForAllCallsigns(int requestId); - //! The situations per callsign //! \threadsafe QHash getSituationsByCallsign() const; + //! Situations for given callsign + //! \threadsafe + BlackMisc::Aviation::CAircraftSituationList getSituationsForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const; + //! Last finished request id, -1 means none //! \threadsafe int latestFinishedRequestId() const; @@ -66,11 +68,26 @@ namespace BlackCore //! \threadsafe BlackMisc::Aviation::CAircraftSituationList getRequest(int requestId, bool *ok = nullptr) const; + //! Enable debug messages + void enableDebugMessages(bool enabled); + static const qint64 TimeOffsetMs = 6000; //!< offset for interpolation static const int MaxSituationsPerCallsign = 6; //!< How many situations per callsign static const int MaxPartsPerCallsign = 3; //!< How many parts per callsign static const int MaxKeptInterpolationRequests = 3; //!< How many requests are stored + public slots: + //! Do a complete calculation for all know callsigns in background. + //! Only use positive numbers. + //! \param currentTimeMsSinceEpoch if no value is passed current time is used + //! \threadsafe + void syncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch = -1); + + //! Do a complete calculation for all know callsigns in background. + //! Non blocking call of \syncRequestSituationsCalculationsForAllCallsigns + //! \threadsafe + void asyncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch = -1); + private slots: //! New situation got added //! \threadsafe @@ -82,7 +99,7 @@ namespace BlackCore //! Removed aircraft //! \threadsafe - void ps_onRemoveAircraft(const BlackMisc::Aviation::CCallsign &callsign); + void ps_onRemovedAircraft(const BlackMisc::Aviation::CCallsign &callsign); protected: //! Constructor @@ -94,7 +111,7 @@ namespace BlackCore //! \deprecated For first version QList getSituationsTimeSplit(const BlackMisc::Aviation::CCallsign &callsign, qint64 splitTimeMsSinceEpoch) const; - bool m_withDebugMsg = true; + bool m_withDebugMsg = false; //!< allows to disable debug messages private: mutable QReadWriteLock m_situationsLock; diff --git a/src/blackcore/interpolator_linear.cpp b/src/blackcore/interpolator_linear.cpp index 1001ae461..eff90fd25 100644 --- a/src/blackcore/interpolator_linear.cpp +++ b/src/blackcore/interpolator_linear.cpp @@ -9,8 +9,10 @@ #include "interpolator_linear.h" #include "blackmisc/avaircraftsituation.h" +#include "blackmisc/logmessage.h" #include +using namespace BlackMisc; using namespace BlackMisc::Geo; using namespace BlackMisc::Math; using namespace BlackMisc::PhysicalQuantities; @@ -18,64 +20,96 @@ using namespace BlackMisc::Aviation; namespace BlackCore { - CAircraftSituation CInterpolatorLinear::getCurrentInterpolatedSituation(const QHash &allSituations, const CCallsign &callsign, bool *ok) const + CAircraftSituation CInterpolatorLinear::getCurrentInterpolatedSituation(const QHash &allSituations, const CCallsign &callsign, qint64 currentTimeMsSinceEpoc, bool *ok) const { const static CAircraftSituation empty; - qint64 splitTimeMsSinceEpoch = QDateTime::currentMSecsSinceEpoch() - TimeOffsetMs; + if (ok) { *ok = false; } + if (!allSituations.contains(callsign)) { return empty; } + if (allSituations[callsign].isEmpty()) { return empty; } + + if (currentTimeMsSinceEpoc < 0) { currentTimeMsSinceEpoc = QDateTime::currentMSecsSinceEpoch(); } + qint64 splitTimeMsSinceEpoch = currentTimeMsSinceEpoc - TimeOffsetMs; QList splitSituations = allSituations[callsign].splitByTime(splitTimeMsSinceEpoch); - CAircraftSituationList &situationsBefore = splitSituations[0]; - CAircraftSituationList &situationsAfter = splitSituations[1]; - if (situationsBefore.isEmpty()) - { - if (ok) { *ok = false; } - return empty; - } + CAircraftSituationList &situationsNewer = splitSituations[0]; // latest first + CAircraftSituationList &situationsOlder = splitSituations[1]; // latest first - CAircraftSituation beginSituation; - CAircraftSituation endSituation; + // interpolation situations + CAircraftSituation oldSituation; + CAircraftSituation newSituation; + int situationsNewerNo = situationsNewer.size(); + int situationsOlderNo = situationsOlder.size(); - // The first condition covers a situation, when there is now future packet. - // So we have to extrapolate. - if (situationsAfter.isEmpty()) + // latest first, now 00:26 -> 00:26 - 6000ms -> 00:20 split time + // time pos + // 00:25 10 newer + // 00:20 11 newer + // <----- split + // 00:15 12 older + // 00:10 13 older + // 00:05 14 older + + // The first condition covers a situation, when there are no before / after situations. + // We just place at he last position until we get before / after situations + if (situationsOlderNo < 1 || situationsNewerNo < 1) { - beginSituation = situationsBefore[situationsBefore.size() - 2]; - endSituation = situationsBefore[situationsBefore.size() - 1]; + if (ok) { *ok = true; } + // no after situations + if (situationsOlderNo < 1) { return situationsNewer.back(); } // oldest newest + + // no before situations + if (situationsOlder.size() < 2) { return situationsOlder.front(); } // latest older + + // this will lead to extrapolation + oldSituation = situationsOlder[1]; // before newest + newSituation = situationsOlder.front(); // newest + } else { - beginSituation = situationsBefore.back(); - endSituation = situationsAfter.front(); + oldSituation = situationsOlder.front(); // first oldest + newSituation = situationsNewer.back(); // latest newest + Q_ASSERT(oldSituation.getMSecsSinceEpoch() < newSituation.getMSecsSinceEpoch()); } - CAircraftSituation currentSituation; + CAircraftSituation currentSituation(oldSituation); CCoordinateGeodetic currentPosition; // Time between start and end packet - double deltaTime = beginSituation.msecsToAbs(endSituation); + double deltaTime = oldSituation.absMsecsTo(newSituation); - // Fraction of the deltaTime [0.0 - 1.0] - double simulationTimeFraction = (beginSituation.getMSecsSinceEpoch() - splitTimeMsSinceEpoch) / deltaTime; + // Fraction of the deltaTime, ideally [0.0 - 1.0] + // < 0 should not happen due to the split, > 1 can happen if new values are delayed beyond split time + // 1) values > 1 mean extrapolation + // 2) values > 2 mean no new situations coming in + double simulationTimeFraction = 1 - ((newSituation.getMSecsSinceEpoch() - splitTimeMsSinceEpoch) / deltaTime); + if (simulationTimeFraction > 1.5) + { + if (this->m_withDebugMsg) + { + CLogMessage(this).warning("Extrapolation, fraction > 1: %1 for callsign: %2") << simulationTimeFraction << callsign; + } + } // Interpolate latitude: Lat = (LatB - LatA) * t + LatA - currentPosition.setLatitude((endSituation.getPosition().latitude() - beginSituation.getPosition().latitude()) + currentPosition.setLatitude((newSituation.getPosition().latitude() - oldSituation.getPosition().latitude()) * simulationTimeFraction - + beginSituation.getPosition().latitude()); + + oldSituation.getPosition().latitude()); // Interpolate latitude: Lon = (LonB - LonA) * t + LonA - currentPosition.setLongitude((endSituation.getPosition().longitude() - beginSituation.getPosition().longitude()) + currentPosition.setLongitude((newSituation.getPosition().longitude() - oldSituation.getPosition().longitude()) * simulationTimeFraction - + beginSituation.getPosition().longitude()); + + oldSituation.getPosition().longitude()); currentSituation.setPosition(currentPosition); // Interpolate altitude: Alt = (AltB - AltA) * t + AltA - currentSituation.setAltitude(CAltitude((endSituation.getAltitude() - beginSituation.getAltitude()) + currentSituation.setAltitude(CAltitude((newSituation.getAltitude() - oldSituation.getAltitude()) * simulationTimeFraction - + beginSituation.getAltitude(), - beginSituation.getAltitude().getReferenceDatum())); + + oldSituation.getAltitude(), + oldSituation.getAltitude().getReferenceDatum())); // Interpolate heading: HDG = (HdgB - HdgA) * t + HdgA - CHeading headingBegin = beginSituation.getHeading(); - CHeading headingEnd = endSituation.getHeading(); + CHeading headingBegin = oldSituation.getHeading(); + CHeading headingEnd = newSituation.getHeading(); if ((headingEnd - headingBegin).value(CAngleUnit::deg()) < -180) { @@ -93,8 +127,8 @@ namespace BlackCore headingBegin.getReferenceNorth())); // Interpolate Pitch: Pitch = (PitchB - PitchA) * t + PitchA - CAngle pitchBegin = beginSituation.getPitch(); - CAngle pitchEnd = endSituation.getPitch(); + CAngle pitchBegin = oldSituation.getPitch(); + CAngle pitchEnd = newSituation.getPitch(); CAngle pitch = (pitchEnd - pitchBegin) * simulationTimeFraction + pitchBegin; // TODO: According to the specification, pitch above horizon should be negative. @@ -103,8 +137,8 @@ namespace BlackCore currentSituation.setPitch(pitch); // Interpolate bank: Bank = (BankB - BankA) * t + BankA - CAngle bankBegin = beginSituation.getBank(); - CAngle bankEnd = endSituation.getBank(); + CAngle bankBegin = oldSituation.getBank(); + CAngle bankEnd = newSituation.getBank(); CAngle bank = (bankEnd - bankBegin) * simulationTimeFraction + bankBegin; // TODO: According to the specification, banks to the right should be negative. @@ -112,10 +146,11 @@ namespace BlackCore bank *= -1; currentSituation.setBank(bank); - currentSituation.setGroundspeed((endSituation.getGroundSpeed() - beginSituation.getGroundSpeed()) + currentSituation.setGroundspeed((newSituation.getGroundSpeed() - oldSituation.getGroundSpeed()) * simulationTimeFraction - + beginSituation.getGroundSpeed()); + + oldSituation.getGroundSpeed()); if (ok) { *ok = true; } + Q_ASSERT(currentSituation.getCallsign() == callsign); return currentSituation; } diff --git a/src/blackcore/interpolator_linear.h b/src/blackcore/interpolator_linear.h index 561cf021a..ff003f267 100644 --- a/src/blackcore/interpolator_linear.h +++ b/src/blackcore/interpolator_linear.h @@ -30,7 +30,11 @@ namespace BlackCore {} //! \copydoc IInterpolator::getCurrentInterpolatedSituation - virtual BlackMisc::Aviation::CAircraftSituation getCurrentInterpolatedSituation(const QHash &allSituations, const BlackMisc::Aviation::CCallsign &callsign, bool *ok = nullptr) const override; + virtual BlackMisc::Aviation::CAircraftSituation getCurrentInterpolatedSituation(const QHash &allSituations, const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc = -1, bool *ok = nullptr) const override; + + //! Log category + static QString getMessageCategory() { return "swift.interpolatorlinear"; } + }; } // namespace BlackCore diff --git a/src/blackmisc/simulation/simdirectaccessremoteaircraft.h b/src/blackmisc/simulation/simdirectaccessremoteaircraft.h index 8026aba67..4da3a1bcb 100644 --- a/src/blackmisc/simulation/simdirectaccessremoteaircraft.h +++ b/src/blackmisc/simulation/simdirectaccessremoteaircraft.h @@ -49,13 +49,13 @@ namespace BlackMisc // those signals have to be implemented by classes using the interface. signals: //! A new situation got added - virtual void addedRemoteAircraftSituation(const BlackMisc::Aviation::CAircraftSituation &situation) = 0; + void addedRemoteAircraftSituation(const BlackMisc::Aviation::CAircraftSituation &situation); //! New parts got added - virtual void addedRemoteAircraftParts(const BlackMisc::Aviation::CAircraftParts &parts) = 0; + void addedRemoteAircraftParts(const BlackMisc::Aviation::CAircraftParts &parts); //! Aircraft was removed - virtual void removedAircraft(const BlackMisc::Aviation::CCallsign &callsign) = 0; + void removedRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign); }; @@ -75,7 +75,7 @@ namespace BlackMisc virtual BlackMisc::Aviation::CAircraftPartsList &remoteAircraftParts() = 0; //! Enable/disable rendering - virtual bool updateAircraftEnabled(const BlackMisc::Aviation::CCallsign &callsign, bool enabledForRedering, const QString &originator) = 0; + virtual bool updateAircraftEnabled(const BlackMisc::Aviation::CCallsign &callsign, bool enabledForRendering, const QString &originator) = 0; //! Change model string virtual bool updateAircraftModel(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Simulation::CAircraftModel &model, const QString &originator) = 0; diff --git a/src/plugins/simulator/fs9/fs9_client.cpp b/src/plugins/simulator/fs9/fs9_client.cpp index ab4027d67..c605eb748 100644 --- a/src/plugins/simulator/fs9/fs9_client.cpp +++ b/src/plugins/simulator/fs9/fs9_client.cpp @@ -82,7 +82,7 @@ namespace BlackSimPlugin bool ok; - CAircraftSituation situation = this->m_interpolator->getCurrentInterpolatedSituation(this->m_interpolator->getSituationsByCallsign(), m_callsign, &ok); + CAircraftSituation situation = this->m_interpolator->getCurrentInterpolatedSituation(this->m_interpolator->getSituationsByCallsign(), m_callsign, -1, &ok); if (!ok) { return; } MPPositionSlewMode positionSlewMode = aircraftSituationToFS9(situation); diff --git a/src/plugins/simulator/fsx/simulator_fsx.cpp b/src/plugins/simulator/fsx/simulator_fsx.cpp index d16e4c75c..398b28761 100644 --- a/src/plugins/simulator/fsx/simulator_fsx.cpp +++ b/src/plugins/simulator/fsx/simulator_fsx.cpp @@ -149,8 +149,8 @@ namespace BlackSimPlugin if (aircraftAlreadyExistsInSim) { // remove first - this->removeRenderedAircraft(callsign); - Q_ASSERT(false); + this->removeRemoteAircraft(callsign); + CLogMessage(this).warning("Have to remove aircraft %1 before I can add it") << callsign; } SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxInitPosition(newRemoteAircraft.getSituation()); @@ -190,12 +190,6 @@ namespace BlackSimPlugin } } - bool CSimulatorFsx::removeRenderedAircraft(const CCallsign &callsign) - { - // only remove from sim - return removeRenderedAircraft(m_simConnectObjects.value(callsign)); - } - bool CSimulatorFsx::updateOwnSimulatorCockpit(const CAircraft &ownAircraft, const QString &originator) { if (originator == this->simulatorOriginator()) { return false; } @@ -352,7 +346,7 @@ namespace BlackSimPlugin void CSimulatorFsx::onSimFrame() { - updateOtherAircraft(); + updateRemoteAircraft(); } void CSimulatorFsx::onSimExit() @@ -511,10 +505,17 @@ namespace BlackSimPlugin } } - bool CSimulatorFsx::removeRenderedAircraft(const CSimConnectObject &simObject) + bool CSimulatorFsx::removeRemoteAircraft(const CCallsign &callsign) + { + // only remove from sim + if (!m_simConnectObjects.contains(callsign)) { return false; } + return removeRemoteAircraft(m_simConnectObjects.value(callsign)); + } + + bool CSimulatorFsx::removeRemoteAircraft(const CSimConnectObject &simObject) { - SimConnect_AIRemoveObject(m_hSimConnect, simObject.getObjectId(), simObject.getRequestId()); m_simConnectObjects.remove(simObject.getCallsign()); + SimConnect_AIRemoveObject(m_hSimConnect, simObject.getObjectId(), simObject.getRequestId()); remoteAircraft().applyIfCallsign(simObject.getCallsign(), CPropertyIndexVariantMap(CSimulatedAircraft::IndexRendered, CVariant::fromValue(false))); CLogMessage(this).info("FSX: Removed aircraft %1") << simObject.getCallsign().toQString(); return true; @@ -594,29 +595,49 @@ namespace BlackSimPlugin return hr; } - void CSimulatorFsx::updateOtherAircraft() + void CSimulatorFsx::updateRemoteAircraft() { static_assert(sizeof(DataDefinitionRemoteAircraft) == 176, "DataDefinitionRemoteAircraft has an incorrect size."); Q_ASSERT(this->m_interpolator); Q_ASSERT_X(this->m_interpolator->thread() != this->thread(), "updateOtherAircraft", "interpolator should run in its own thread"); - bool lastRequestAvailable; + // nothing to do, reset request id and exit + int remoteAircraftNo = this->remoteAircraft().size(); + if (remoteAircraftNo < 1) { m_interpolationRequest = 0; return; } + + // initial request, and bye. First time we have aircraft + if (m_interpolationRequest == 0) + { + m_interpolator->syncRequestSituationsCalculationsForAllCallsigns(++m_interpolationRequest); + return; + } + + // try to get old request + bool lastRequestAvailable = false; CAircraftSituationList interpolations = m_interpolator->getRequest(m_interpolationRequest, &lastRequestAvailable); if (!lastRequestAvailable) { + // warning the 1st and every 10th time + bool warning = m_interpolationsSkipped % 10; m_interpolationsSkipped++; + if (warning) + { + CLogMessage(this).warning("Skipped interpolation %1 time(s)") << m_interpolationsSkipped; + } return; } // non blocking calculations in background - m_interpolator->requestSituationsCalculationsForAllCallsigns(m_interpolationsSkipped); + m_interpolator->syncRequestSituationsCalculationsForAllCallsigns(++m_interpolationRequest); // now send to sim for (const CAircraftSituation ¤tSituation : interpolations) { - bool hasParts; const CCallsign callsign(currentSituation.getCallsign()); + if (!m_simConnectObjects.contains(callsign)) { continue; } // only if aircraft is already available + bool hasParts; const CSimConnectObject &simObj = m_simConnectObjects[callsign]; + if (simObj.getObjectId() == 0) { continue; } SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxInitPosition(currentSituation); CAircraftParts parts = m_interpolator->getLatestPartsBeforeOffset(callsign, IInterpolator::TimeOffsetMs, &hasParts); @@ -625,7 +646,6 @@ namespace BlackSimPlugin { // we have parts position.OnGround = parts.isOnGround() ? 1 : 0; - ddRemoteAircraft.position = position; ddRemoteAircraft.lightStrobe = parts.getLights().isStrobeOn() ? 1.0 : 0.0; ddRemoteAircraft.lightLanding = parts.getLights().isLandingOn() ? 1.0 : 0.0; @@ -639,27 +659,49 @@ namespace BlackSimPlugin ddRemoteAircraft.flapsTrailingEdgeRightPercent = parts.getFlapsPercent() / 100.0; ddRemoteAircraft.spoilersHandlePosition = parts.isSpoilersOut() ? 1.0 : 0.0; ddRemoteAircraft.gearHandlePosition = parts.isGearDown() ? 1 : 0; - ddRemoteAircraft.engine1Combustion = parts.getEngines().findBy(&CAircraftEngine::getNumber, 1).frontOrDefault().isOn() ? 1 : 0; - ddRemoteAircraft.engine2Combustion = parts.getEngines().findBy(&CAircraftEngine::getNumber, 2).frontOrDefault().isOn() ? 1 : 0; - ddRemoteAircraft.engine3Combustion = parts.getEngines().findBy(&CAircraftEngine::getNumber, 3).frontOrDefault().isOn() ? 1 : 0; - ddRemoteAircraft.engine4Combustion = parts.getEngines().findBy(&CAircraftEngine::getNumber, 4).frontOrDefault().isOn() ? 1 : 0; + ddRemoteAircraft.engine1Combustion = parts.isEngineOn(1) ? 1 : 0; + ddRemoteAircraft.engine2Combustion = parts.isEngineOn(2) ? 1 : 0;; + ddRemoteAircraft.engine3Combustion = parts.isEngineOn(3) ? 1 : 0; + ddRemoteAircraft.engine4Combustion = parts.isEngineOn(4) ? 1 : 0; } else { //! \todo interpolator, set data without parts by educated guessing whatsoever - position.OnGround = parts.isOnGround() ? 1 : 0; + bool onGround = currentSituation.isOnGroundGuessed(); + position.OnGround = onGround ? 1 : 0; + ddRemoteAircraft.position = position; + ddRemoteAircraft.gearHandlePosition = onGround ? 1 : 0; + + // when first detected moving, lights on + if (onGround && currentSituation.getGroundSpeed().value(CSpeedUnit::km_h()) > 15) + { + // ddRemoteAircraft.light = 1.0; + ddRemoteAircraft.lightBeacon = 1.0; + ddRemoteAircraft.lightNav = 1.0; + ddRemoteAircraft.lightLanding = 0.0; + } + else if (onGround) + { + // ddRemoteAircraft.lightTaxi = 0.0; + ddRemoteAircraft.lightBeacon = 1.0; + ddRemoteAircraft.lightNav = 1.0; + ddRemoteAircraft.lightLanding = 0.0; + } + else if (!onGround) + { + // ddRemoteAircraft.lightTaxi = 0.0; + ddRemoteAircraft.lightBeacon = 1.0; + ddRemoteAircraft.lightNav = 1.0; + } } - if (simObj.getObjectId() != 0) - { - HRESULT hr = S_OK; - hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, - simObj.getObjectId(), 0, 0, - sizeof(DataDefinitionRemoteAircraft), &ddRemoteAircraft); + HRESULT hr = S_OK; + hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, + simObj.getObjectId(), 0, 0, + sizeof(DataDefinitionRemoteAircraft), &ddRemoteAircraft); - if (hr != S_OK) { CLogMessage(this).warning("Failed so set data on SimObject"); } - } - } // ok, no parts + if (hr != S_OK) { CLogMessage(this).warning("Failed so set data on SimObject"); } + } // all situations } SIMCONNECT_DATA_INITPOSITION CSimulatorFsx::aircraftSituationToFsxInitPosition(const CAircraftSituation &situation)