diff --git a/src/blackcore/airspace_monitor.cpp b/src/blackcore/airspace_monitor.cpp index 2adb80464..d2c0c2ca8 100644 --- a/src/blackcore/airspace_monitor.cpp +++ b/src/blackcore/airspace_monitor.cpp @@ -919,12 +919,8 @@ namespace BlackCore this->m_aircraftParts.removeOlderThanNowMinusOffset(AircraftPartsRemoveOffsetMs); emit this->addedRemoteAircraftParts(parts); - CPropertyIndexVariantMap vm; - vm.addValue(CAircraft::IndexParts, parts); - vm.addValue(CSimulatedAircraft::IndexPartsSynchronized, true); - // here I expect always a changed value - this->m_aircraftInRange.applyIfCallsign(callsign, vm); + this->m_aircraftInRange.setAircraftParts(callsign, parts); this->m_aircraftWatchdog.resetCallsign(callsign); } diff --git a/src/blackcore/context_network.h b/src/blackcore/context_network.h index b92d8a33e..393601445 100644 --- a/src/blackcore/context_network.h +++ b/src/blackcore/context_network.h @@ -96,10 +96,14 @@ namespace BlackCore void changedAircraftInRangeDigest(); //! Aircraft model was changed - void changedRenderedAircraftModel(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator); + //! \details All remote aircraft are stored in the network context. The model can be updated here + //! via \sa updateAircraftModel and then this signal is fired + void changedRemoteAircraftModel(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator); //! Aircraft enabled / disabled - void changedAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator); + //! \details All remote aircraft are stored in the network context. The aircraft can be enabled (for rendering) here + //! via \sa updateAircraftEnabled and then this signal is fired + void changedRemoteAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator); //! Aircraft enabled / disabled void changedFastPositionUpdates(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator); diff --git a/src/blackcore/context_network_impl.cpp b/src/blackcore/context_network_impl.cpp index bb820d197..fd24ec501 100644 --- a/src/blackcore/context_network_impl.cpp +++ b/src/blackcore/context_network_impl.cpp @@ -522,7 +522,7 @@ namespace BlackCore if (c) { CSimulatedAircraft aircraft(this->remoteAircraft().findFirstByCallsign(callsign)); - emit this->changedAircraftEnabled(aircraft, originator); + emit this->changedRemoteAircraftEnabled(aircraft, originator); } return c; } @@ -534,7 +534,7 @@ namespace BlackCore if (c) { CSimulatedAircraft aircraft(this->remoteAircraft().findFirstByCallsign(callsign)); - emit this->changedRenderedAircraftModel(aircraft, originator); + emit this->changedRemoteAircraftModel(aircraft, originator); } return c; } diff --git a/src/blackcore/context_network_proxy.cpp b/src/blackcore/context_network_proxy.cpp index 198930459..48395a879 100644 --- a/src/blackcore/context_network_proxy.cpp +++ b/src/blackcore/context_network_proxy.cpp @@ -76,10 +76,10 @@ namespace BlackCore "vatsimBookingsRead", this, SIGNAL(vatsimBookingsRead())); Q_ASSERT(s); s = connection.connect(serviceName, IContextNetwork::ObjectPath(), IContextNetwork::InterfaceName(), - "changedRenderedAircraftModel", this, SIGNAL(changedRenderedAircraftModel(BlackMisc::Simulation::CSimulatedAircraft, QString))); + "changedRemoteAircraftModel", this, SIGNAL(changedRemoteAircraftModel(BlackMisc::Simulation::CSimulatedAircraft, QString))); Q_ASSERT(s); s = connection.connect(serviceName, IContextNetwork::ObjectPath(), IContextNetwork::InterfaceName(), - "changedAircraftEnabled", this, SIGNAL(changedAircraftEnabled(BlackMisc::Simulation::CSimulatedAircraft, QString))); + "changedRemoteAircraftEnabled", this, SIGNAL(changedRemoteAircraftEnabled(BlackMisc::Simulation::CSimulatedAircraft, QString))); Q_ASSERT(s); s = connection.connect(serviceName, IContextNetwork::ObjectPath(), IContextNetwork::InterfaceName(), "changedFastPositionUpdates", this, SIGNAL(changedFastPositionUpdates(BlackMisc::Simulation::CSimulatedAircraft,QString))); diff --git a/src/blackcore/context_ownaircraft_impl.cpp b/src/blackcore/context_ownaircraft_impl.cpp index ef9949b31..231339a7a 100644 --- a/src/blackcore/context_ownaircraft_impl.cpp +++ b/src/blackcore/context_ownaircraft_impl.cpp @@ -88,9 +88,9 @@ namespace BlackCore Q_ASSERT(this->getIContextAudio()); Q_ASSERT(this->getIContextNetwork()); Q_ASSERT(this->getIContextApplication()); - if (!this->getIContextNetwork() || !this->getIContextAudio() || !this->getIContextAudio()) { return; } // no chance to resolve rooms + if (!this->getIContextNetwork() || !this->getIContextAudio() || !this->getIContextApplication()) { return; } // no chance to resolve rooms - CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; + if (m_debugEnabled) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; } if (this->m_voiceRoom1UrlOverride.isEmpty() && this->m_voiceRoom2UrlOverride.isEmpty() && !this->m_automaticVoiceRoomResolution) { return; } if (!this->m_automaticVoiceRoomResolution) { return; } // not responsible diff --git a/src/blackcore/context_simulator.cpp b/src/blackcore/context_simulator.cpp index 8c2aea83e..5841dd523 100644 --- a/src/blackcore/context_simulator.cpp +++ b/src/blackcore/context_simulator.cpp @@ -11,9 +11,29 @@ #include "context_simulator_impl.h" #include "context_simulator_proxy.h" +using namespace BlackMisc::PhysicalQuantities; + namespace BlackCore { + const QString &IContextSimulator::InterfaceName() + { + static const QString s(BLACKCORE_CONTEXTSIMULATOR_INTERFACENAME); + return s; + } + + const QString &IContextSimulator::ObjectPath() + { + static const QString s(BLACKCORE_CONTEXTSIMULATOR_OBJECTPATH); + return s; + } + + const BlackMisc::PhysicalQuantities::CTime &IContextSimulator::HighlightTime() + { + static const CTime t(10.0, CTimeUnit::s()); + return t; + } + IContextSimulator *IContextSimulator::create(CRuntime *parent, CRuntimeConfig::ContextMode mode, CDBusServer *server, QDBusConnection &conn) { switch (mode) diff --git a/src/blackcore/context_simulator.h b/src/blackcore/context_simulator.h index a7fad6ea1..551bdb5ee 100644 --- a/src/blackcore/context_simulator.h +++ b/src/blackcore/context_simulator.h @@ -34,6 +34,7 @@ #include "blackmisc/avairportlist.h" #include "blackmisc/project.h" #include "blackmisc/pixmap.h" +#include "blackmisc/pqtime.h" #include namespace BlackCore @@ -46,18 +47,13 @@ namespace BlackCore public: //! Service name - static const QString &InterfaceName() - { - static QString s(BLACKCORE_CONTEXTSIMULATOR_INTERFACENAME); - return s; - } + static const QString &InterfaceName(); //! Service path - static const QString &ObjectPath() - { - static QString s(BLACKCORE_CONTEXTSIMULATOR_OBJECTPATH); - return s; - } + static const QString &ObjectPath(); + + //! Highlight time + static const BlackMisc::PhysicalQuantities::CTime &HighlightTime(); //! \copydoc CContext::getPathAndContextId() virtual QString getPathAndContextId() const { return this->buildPathAndContextId(ObjectPath()); } @@ -172,6 +168,9 @@ namespace BlackCore //! Enable debugging virtual void enableDebugMessages(bool driver, bool interpolator) = 0; + //! Highlight aircraft in simulator + virtual void highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime) = 0; + protected: //! Constructor IContextSimulator(CRuntimeConfig::ContextMode mode, CRuntime *runtime) : CContext(mode, runtime) {} diff --git a/src/blackcore/context_simulator_impl.cpp b/src/blackcore/context_simulator_impl.cpp index a6faa8077..f5f4fc0b1 100644 --- a/src/blackcore/context_simulator_impl.cpp +++ b/src/blackcore/context_simulator_impl.cpp @@ -248,13 +248,14 @@ namespace BlackCore Q_ASSERT(networkContext->isLocalObject()); // use readyForModelMatching instead of CAirspaceMonitor::addedAircraft, as it contains client information + // ready for model matching is sent delayed when all information are available bool c = connect(networkContext, &IContextNetwork::readyForModelMatching, this, &CContextSimulator::ps_addRemoteAircraft); Q_ASSERT(c); c = connect(networkContext, &IContextNetwork::removedAircraft, this, &CContextSimulator::ps_removedRemoteAircraft); Q_ASSERT(c); - c = connect(networkContext, &IContextNetwork::changedRenderedAircraftModel, this->m_simulator, &ISimulator::changeRemoteAircraftModel); + c = connect(networkContext, &IContextNetwork::changedRemoteAircraftModel, this, &CContextSimulator::ps_changedRemoteAircraftModel); Q_ASSERT(c); - c = connect(networkContext, &IContextNetwork::changedAircraftEnabled, this->m_simulator, &ISimulator::changeAircraftEnabled); + c = connect(networkContext, &IContextNetwork::changedRemoteAircraftEnabled, this, &CContextSimulator::ps_changedRemoteAircraftEnabled); Q_ASSERT(c); Q_UNUSED(c); @@ -366,6 +367,22 @@ namespace BlackCore this->getIContextOwnAircraft()->changedAircraftCockpit(ownAircraft, IContextSimulator::InterfaceName()); } + void CContextSimulator::ps_changedRemoteAircraftModel(const CSimulatedAircraft &aircraft, const QString &originator) + { + Q_ASSERT(this->m_simulator); + if (!this->m_simulator) { return; } + + this->m_simulator->changeRemoteAircraftModel(aircraft, originator); + } + + void CContextSimulator::ps_changedRemoteAircraftEnabled(const CSimulatedAircraft &aircraft, const QString &originator) + { + Q_ASSERT(this->m_simulator); + if (!this->m_simulator) { return; } + + this->m_simulator->changeRemoteAircraftEnabled(aircraft, originator); + } + void CContextSimulator::ps_updateSimulatorCockpitFromContext(const CAircraft &ownAircraft, const QString &originator) { Q_ASSERT(this->m_simulator); @@ -419,6 +436,12 @@ namespace BlackCore return this->m_simulator->enableDebugMessages(driver, interpolator); } + void CContextSimulator::highlightAircraft(const CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const CTime &displayTime) + { + if (!this->m_simulator) { return; } + this->m_simulator->highlightAircraft(aircraftToHighlight, enableHighlight, displayTime); + } + bool CContextSimulator::isPaused() const { if (!this->m_simulator) return false; diff --git a/src/blackcore/context_simulator_impl.h b/src/blackcore/context_simulator_impl.h index fec3b1ef4..f9295b4a5 100644 --- a/src/blackcore/context_simulator_impl.h +++ b/src/blackcore/context_simulator_impl.h @@ -119,6 +119,9 @@ namespace BlackCore //! \copydoc ISimulator::enableDebuggingMessages virtual void enableDebugMessages(bool driver, bool interpolator) override; + //! \copydoc IContextSimulator::highlightAircraft + virtual void highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime) override; + protected: //! \brief Constructor CContextSimulator(CRuntimeConfig::ContextMode, CRuntime *runtime); @@ -132,13 +135,13 @@ namespace BlackCore } private slots: - //! \copydoc ISimulator::addRemoteAircraft + //! Remote aircraft added void ps_addRemoteAircraft(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft); - //! \copydoc ISimulator::removeRemoteAircraft + //! Remove remote aircraft void ps_removedRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign); - //! Handle new connection status + //! Handle new connection status of simulator void ps_onConnectionStatusChanged(ISimulator::ConnectionStatus status); //! Text message received @@ -147,6 +150,12 @@ namespace BlackCore //! Simulator has changed cockpit void ps_cockitChangedFromSim(const BlackMisc::Simulation::CSimulatedAircraft &ownAircraft); + //! Changed remote aircraft model + void ps_changedRemoteAircraftModel(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator); + + //! Enable / disable aircraft + void ps_changedRemoteAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator); + //! Update simulator cockpit from context, because someone else has changed cockpit (e.g. GUI, 3rd party) //! \remarks set by runtime, only to be used locally (not via DBus) void ps_updateSimulatorCockpitFromContext(const BlackMisc::Aviation::CAircraft &ownAircraft, const QString &originator); @@ -161,6 +170,6 @@ namespace BlackCore QFuture m_canConnectResult; }; -} // namespace BlackCore +} // namespace #endif // guard diff --git a/src/blackcore/context_simulator_proxy.cpp b/src/blackcore/context_simulator_proxy.cpp index 0b8dc7e0c..4ad29508a 100644 --- a/src/blackcore/context_simulator_proxy.cpp +++ b/src/blackcore/context_simulator_proxy.cpp @@ -169,6 +169,11 @@ namespace BlackCore return m_dBusInterface->callDBusRet(QLatin1Literal("iconForModel"), modelString); } + void CContextSimulatorProxy::highlightAircraft(const CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const CTime &displayTime) + { + m_dBusInterface->callDBus(QLatin1Literal("highlightAircraft"), aircraftToHighlight, enableHighlight, displayTime); + } + void CContextSimulatorProxy::enableDebugMessages(bool driver, bool interpolator) { m_dBusInterface->callDBus(QLatin1Literal("enableDebugMessages"), driver, interpolator); diff --git a/src/blackcore/context_simulator_proxy.h b/src/blackcore/context_simulator_proxy.h index 0c8613f81..2cd83bdfe 100644 --- a/src/blackcore/context_simulator_proxy.h +++ b/src/blackcore/context_simulator_proxy.h @@ -119,6 +119,9 @@ namespace BlackCore //! \copydoc IContextSimulator::iconForModel virtual BlackMisc::CPixmap iconForModel(const QString &modelString) const override; + //! \copydoc IContextSimulator::highlightAircraft + virtual void highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime) override; + //! \copydoc ISimulator::enableDebuggingMessages virtual void enableDebugMessages(bool driver, bool interpolator) override; diff --git a/src/blackcore/interpolator.cpp b/src/blackcore/interpolator.cpp index d50dd5b3b..e6d05573a 100644 --- a/src/blackcore/interpolator.cpp +++ b/src/blackcore/interpolator.cpp @@ -75,6 +75,7 @@ namespace BlackCore if (this->m_partsByCallsign.contains(callsign)) { partsStatus.supportsParts = true; + if (cutoffTime < 0) { return this->m_partsByCallsign[callsign]; } return this->m_partsByCallsign[callsign].findBeforeAndRemove(cutoffTime); } else @@ -93,6 +94,16 @@ namespace BlackCore m_partsByCallsign.clear(); } + bool IInterpolator::hasDataForCallsign(const CCallsign &callsign) const + { + if (callsign.isEmpty()) { return false; } + QReadLocker s(&m_lockSituations); + if (m_situationsByCallsign.contains(callsign)) { return true; } + + QReadLocker p(&m_lockParts); + return m_partsByCallsign.contains(callsign); + } + CAircraftSituationList IInterpolator::getSituationsForCallsign(const CCallsign &callsign) const { QReadLocker l(&m_lockSituations); diff --git a/src/blackcore/interpolator.h b/src/blackcore/interpolator.h index cf2559780..0b6152d75 100644 --- a/src/blackcore/interpolator.h +++ b/src/blackcore/interpolator.h @@ -15,7 +15,6 @@ #include "blackmisc/avaircraftsituation.h" #include "blackmisc/simulation/simdirectaccessremoteaircraft.h" #include "blackmisc/worker.h" -#include "simulator.h" #include #include @@ -39,7 +38,7 @@ namespace BlackCore virtual ~IInterpolator() {} //! Log category - static QString getMessageCategory() { return "swift.iinterpolator"; } + static QString getMessageCategory() { return "swift.interpolator"; } //! Status of interpolation struct InterpolationStatus @@ -79,23 +78,28 @@ namespace BlackCore //! virtual BlackMisc::Aviation::CAircraftSituationList getInterpolatedSituations(qint64 currentTimeMsSinceEpoch = -1); - //! The situations per callsign + //! All situations for all callsigns (in map as per callsign) //! \threadsafe CSituationsPerCallsign getSituationsByCallsign() const; //! Parts before given offset time (aka pending parts) + //! \note //! \threadsafe - virtual BlackMisc::Aviation::CAircraftPartsList getAndRemovePartsBeforeTime(const BlackMisc::Aviation::CCallsign &callsign, qint64 timeOffset, PartsStatus &partsStatus); + virtual BlackMisc::Aviation::CAircraftPartsList getAndRemovePartsBeforeTime(const BlackMisc::Aviation::CCallsign &callsign, qint64 cutoffTime, PartsStatus &partsStatus); //! Clear all data //! \threadsafe virtual void clear(); - //! Situations for given callsign + //! Knows callsign? + //! \threadsafe + virtual bool hasDataForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const; + + //! All situations for given callsign //! \threadsafe BlackMisc::Aviation::CAircraftSituationList getSituationsForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const; - //! Parts for given callsign + //! All parts for given callsign //! \threadsafe BlackMisc::Aviation::CAircraftPartsList getPartsForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const; diff --git a/src/blackcore/simulator.cpp b/src/blackcore/simulator.cpp index ceeb25d26..f1a76ae55 100644 --- a/src/blackcore/simulator.cpp +++ b/src/blackcore/simulator.cpp @@ -8,8 +8,11 @@ */ #include "simulator.h" +#include "interpolator.h" using namespace BlackMisc::Aviation; +using namespace BlackMisc::Simulation; +using namespace BlackMisc::PhysicalQuantities; using namespace BlackSim; namespace BlackCore @@ -21,7 +24,80 @@ namespace BlackCore CSimulatorCommon::CSimulatorCommon(const BlackSim::CSimulatorInfo &simInfo, BlackMisc::Simulation::IOwnAircraftProvider *ownAircraftProvider, BlackMisc::Simulation::IRemoteAircraftProvider *remoteAircraftProvider, QObject *parent) : ISimulator(parent), COwnAircraftProviderSupport(ownAircraftProvider), CRemoteAircraftProviderSupport(remoteAircraftProvider), m_simulatorInfo(simInfo) - { } + { + m_oneSecondTimer = new QTimer(this); + connect(this->m_oneSecondTimer, &QTimer::timeout, this, &CSimulatorCommon::ps_oneSecondTimer); + m_oneSecondTimer->start(1000); + } + + void CSimulatorCommon::blinkHighlightedAircraft() + { + if (m_highlightedAircraft.isEmpty() || m_highlightEndTimeMsEpoch < 1) { return; } + m_blinkCycle = !m_blinkCycle; + + if (QDateTime::currentMSecsSinceEpoch() < m_highlightEndTimeMsEpoch) + { + // blink mode, toggle aircraft + for (const CSimulatedAircraft &aircraft : m_highlightedAircraft) + { + if (m_blinkCycle) + { + this->removeRemoteAircraft(aircraft.getCallsign()); + } + else + { + this->addRemoteAircraft(aircraft); + } + } + } + else + { + // restore + for (const CSimulatedAircraft &aircraft : m_highlightedAircraft) + { + // get the current state for this aircraft + // it might has been removed in the mean time + const CCallsign cs(aircraft.getCallsign()); + resetAircraftFromBacked(cs); + } + m_highlightedAircraft.clear(); + m_highlightEndTimeMsEpoch = 0; + } + } + + void CSimulatorCommon::resetAircraftFromBacked(const CCallsign &callsign) + { + CSimulatedAircraft aircraft(this->remoteAircraft().findFirstByCallsign(callsign)); + bool enabled = aircraft.isEnabled(); + if (enabled) + { + // are we already visible? + if (!isRenderedAircraft(callsign)) + { + this->addRemoteAircraft(aircraft); + } + } + else + { + removeRemoteAircraft(callsign); + } + } + + void CSimulatorCommon::setInitialAircraftSituationAndParts(CSimulatedAircraft &aircraft) const + { + if (!this->m_interpolator) { return; } + + const CCallsign callsign(aircraft.getCallsign()); + if (!this->m_interpolator->hasDataForCallsign(callsign)) { return; } + + // with an interpolator the interpolated situation is used + // to avoid position jittering + qint64 time = QDateTime::currentMSecsSinceEpoch(); + IInterpolator::InterpolationStatus is; + CAircraftSituation as(m_interpolator->getInterpolatedSituation(callsign, time, is)); + if (is.interpolationSucceeded) { aircraft.setSituation(as); } + + } int CSimulatorCommon::getMaxRenderedAircraft() const { @@ -50,4 +126,26 @@ namespace BlackCore return getInstalledModels().size(); } + void CSimulatorCommon::highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime) + { + CCallsign cs(aircraftToHighlight.getCallsign()); + this->m_highlightedAircraft.removeByCallsign(cs); + if (enableHighlight) + { + qint64 deltaT = displayTime.valueRounded(CTimeUnit::ms(), 0); + this->m_highlightEndTimeMsEpoch = QDateTime::currentMSecsSinceEpoch() + deltaT; + this->m_highlightedAircraft.push_back(aircraftToHighlight); + } + } + + bool CSimulatorCommon::isRenderingEnabled() const + { + return m_maxRenderedAircraft < 1; + } + + void CSimulatorCommon::ps_oneSecondTimer() + { + blinkHighlightedAircraft(); + } + } // namespace diff --git a/src/blackcore/simulator.h b/src/blackcore/simulator.h index 8a0f8b685..03cfa47e5 100644 --- a/src/blackcore/simulator.h +++ b/src/blackcore/simulator.h @@ -12,6 +12,7 @@ #ifndef BLACKCORE_SIMULATOR_H #define BLACKCORE_SIMULATOR_H +#include "blackcore/interpolator.h" #include "blacksim/simulatorinfo.h" #include "blackmisc/simulation/simulatedaircraftlist.h" #include "blackmisc/simulation/aircraftmodellist.h" @@ -26,6 +27,7 @@ namespace BlackCore { + //! Interface to a simulator. class ISimulator : public QObject { @@ -80,16 +82,20 @@ namespace BlackCore virtual bool disconnectFrom() = 0; //! Add new remote aircraft to the simulator + //! \sa changeRemoteAircraftEnabled to hide a remote aircraft virtual bool addRemoteAircraft(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft) = 0; //! Remove remote aircraft from simulator virtual bool removeRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) = 0; + //! Remove all remote aircraft + virtual void removeAllRemoteAircraft() = 0; + //! Change remote aircraft per property virtual bool changeRemoteAircraftModel(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator) = 0; //! Aircraft got enabled / disabled - virtual bool changeAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator) = 0; + virtual bool changeRemoteAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator) = 0; //! Update own aircraft cockpit (usually from context) virtual bool updateOwnSimulatorCockpit(const BlackMisc::Aviation::CAircraft &aircraft, const QString &originator) = 0; @@ -137,6 +143,15 @@ namespace BlackCore //! Enable debugging messages virtual void enableDebugMessages(bool driver, bool interpolator) = 0; + //! Is the aircraft rendered (displayed in simulator)? + virtual bool isRenderedAircraft(const BlackMisc::Aviation::CCallsign &callsign) const = 0; + + //! Highlight the aircraft for given time (or disable highlight) + virtual void highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime) = 0; + + //! Is rendering enabled + virtual bool isRenderingEnabled() const = 0; + signals: //! Emitted when the connection status has changed void connectionStatusChanged(ISimulator::ConnectionStatus status); @@ -197,7 +212,7 @@ namespace BlackCore class CSimulatorCommon : public BlackCore::ISimulator, public BlackMisc::Simulation::COwnAircraftProviderSupport, // gain access to in memor own aircraft data - public BlackMisc::Simulation::CRemoteAircraftProviderSupport // gain access to in memory rendered aircraft data + public BlackMisc::Simulation::CRemoteAircraftProviderSupport // gain access to in memory remote aircraft data { Q_OBJECT @@ -219,6 +234,16 @@ namespace BlackCore //! \copydoc ISimulator::getInstalledModelsCount virtual int getInstalledModelsCount() const override; + //! \copydoc IContextSimulator::highlightAircraft + virtual void highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime) override; + + //! \copydoc IContextSimulator::isRenderingEnabled + virtual bool isRenderingEnabled() const override; + + protected slots: + //! Slow timer used to highlight aircraft, can be used for other things too + virtual void ps_oneSecondTimer(); + protected: //! Constructor CSimulatorCommon( @@ -227,10 +252,26 @@ namespace BlackCore BlackMisc::Simulation::IRemoteAircraftProvider *remoteAircraftProvider, QObject *parent = nullptr); + + //! Blink the highlighted aircraft + void blinkHighlightedAircraft(); + + //! Restore aircraft from backedn 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; + BlackSim::CSimulatorInfo m_simulatorInfo; //!< about the simulator - int m_maxRenderedAircraft = 99; //!< max. rendered aircraft + int m_maxRenderedAircraft = 90; //!< max. rendered aircraft bool m_debugMessages = false; //!< Display debug messages - BlackMisc::Aviation::CCallsignList m_callsignsToBeRendered; //!< all other aircraft are to be ignored + bool m_blinkCycle = false; //!< use for highlighting + IInterpolator *m_interpolator = nullptr; //!< interpolator instance + qint64 m_highlightEndTimeMsEpoch = 0; + BlackMisc::Simulation::CSimulatedAircraftList m_highlightedAircraft; //!< all other aircraft are to be ignored + BlackMisc::Aviation::CCallsignList m_callsignsToBeRendered; + QTimer *m_oneSecondTimer = nullptr; + }; } // namespace diff --git a/src/blackgui/components/aircraftcomponent.cpp b/src/blackgui/components/aircraftcomponent.cpp index 760b4ac42..9d8ec0920 100644 --- a/src/blackgui/components/aircraftcomponent.cpp +++ b/src/blackgui/components/aircraftcomponent.cpp @@ -20,6 +20,7 @@ using namespace BlackGui::Views; using namespace BlackGui::Models; using namespace BlackCore; using namespace BlackMisc::Simulation; +using namespace BlackMisc::PhysicalQuantities; namespace BlackGui { @@ -33,11 +34,14 @@ namespace BlackGui ui->setupUi(this); this->tabBar()->setExpanding(false); this->ui->tvp_AirportsInRange->setResizeMode(CAirportView::ResizingOnce); + m_updateTimer = new CUpdateTimer(&CAircraftComponent::update, this); this->ui->tvp_AircraftInRange->setAircraftMode(CSimulatedAircraftListModel::InfoMode); + this->ui->tvp_AircraftInRange->configureMenu(true, false, false); connect(this->ui->tvp_AircraftInRange, &CSimulatedAircraftView::rowCountChanged, this, &CAircraftComponent::ps_onRowCountChanged); connect(this->ui->tvp_AircraftInRange, &CSimulatedAircraftView::requestTextMessageWidget, this, &CAircraftComponent::requestTextMessageWidget); + connect(this->ui->tvp_AircraftInRange, &CSimulatedAircraftView::requestHighlightInSimulator, this, &CAircraftComponent::ps_onMenuHighlightInSimulator); connect(this->ui->tvp_AirportsInRange, &CSimulatedAircraftView::rowCountChanged, this, &CAircraftComponent::ps_onRowCountChanged); } @@ -125,5 +129,13 @@ namespace BlackGui } } + void CAircraftComponent::ps_onMenuHighlightInSimulator(const CSimulatedAircraft &aircraft) + { + if (getIContextSimulator()) + { + getIContextSimulator()->highlightAircraft(aircraft, true, IContextSimulator::HighlightTime()); + } + } + } // namespace } // namespace diff --git a/src/blackgui/components/aircraftcomponent.h b/src/blackgui/components/aircraftcomponent.h index 7eeea4ada..432c7e9ff 100644 --- a/src/blackgui/components/aircraftcomponent.h +++ b/src/blackgui/components/aircraftcomponent.h @@ -80,6 +80,9 @@ namespace BlackGui //! Connection status has been changed void ps_connectionStatusChanged(int from, int to); + //! Highlight in simulator + void ps_onMenuHighlightInSimulator(const BlackMisc::Simulation::CSimulatedAircraft &aircraft); + private: QScopedPointer ui; CUpdateTimer *m_updateTimer = nullptr; diff --git a/src/blackgui/components/mappingcomponent.cpp b/src/blackgui/components/mappingcomponent.cpp index 5827edf25..5efde405c 100644 --- a/src/blackgui/components/mappingcomponent.cpp +++ b/src/blackgui/components/mappingcomponent.cpp @@ -24,6 +24,7 @@ using namespace BlackMisc; using namespace BlackMisc::Simulation; using namespace BlackMisc::Network; using namespace BlackMisc::Aviation; +using namespace BlackMisc::PhysicalQuantities; using namespace BlackCore; using namespace BlackGui; using namespace BlackGui::Views; @@ -54,6 +55,7 @@ namespace BlackGui connect(this->ui->tvp_SimulatedAircraft, &CSimulatedAircraftView::requestTextMessageWidget, this, &CMappingComponent::requestTextMessageWidget); connect(this->ui->tvp_SimulatedAircraft, &CSimulatedAircraftView::requestEnableAircraft, this, &CMappingComponent::ps_onMenuEnableAircraft); connect(this->ui->tvp_SimulatedAircraft, &CSimulatedAircraftView::requestFastPositionUpdates, this, &CMappingComponent::ps_onMenuChangeFastPositionUpdates); + connect(this->ui->tvp_SimulatedAircraft, &CSimulatedAircraftView::requestHighlightInSimulator, this, &CMappingComponent::ps_onMenuHighlightInSimulator); connect(this->ui->pb_SaveAircraft, &QPushButton::clicked, this, &CMappingComponent::ps_onSaveAircraft); @@ -93,8 +95,8 @@ namespace BlackGui Q_ASSERT(getIContextNetwork()); connect(getIContextSimulator(), &IContextSimulator::installedAircraftModelsChanged, this, &CMappingComponent::ps_onAircraftModelsLoaded); connect(getIContextSimulator(), &IContextSimulator::modelMatchingCompleted, this, &CMappingComponent::ps_onModelMatchingCompleted); - connect(getIContextNetwork(), &IContextNetwork::changedRenderedAircraftModel, this, &CMappingComponent::ps_onRenderedAircraftModelChanged); - connect(getIContextNetwork(), &IContextNetwork::changedAircraftEnabled, this, &CMappingComponent::ps_onChangedAircraftEnabled); + connect(getIContextNetwork(), &IContextNetwork::changedRemoteAircraftModel, this, &CMappingComponent::ps_onRenderedAircraftModelChanged); + connect(getIContextNetwork(), &IContextNetwork::changedRemoteAircraftEnabled, this, &CMappingComponent::ps_onChangedAircraftEnabled); connect(getIContextNetwork(), &IContextNetwork::changedFastPositionUpdates, this, &CMappingComponent::ps_onFastPositionUpdatesEnabled); connect(getIContextNetwork(), &IContextNetwork::connectionStatusChanged, this, &CMappingComponent::ps_onConnectionStatusChanged); @@ -339,6 +341,14 @@ namespace BlackGui } } + void CMappingComponent::ps_onMenuHighlightInSimulator(const CSimulatedAircraft &aircraft) + { + if (getIContextSimulator()) + { + getIContextSimulator()->highlightAircraft(aircraft, true, IContextSimulator::HighlightTime()); + } + } + void CMappingComponent::ps_onMenuEnableAircraft(const CSimulatedAircraft &aircraft) { if (getIContextNetwork()) diff --git a/src/blackgui/components/mappingcomponent.h b/src/blackgui/components/mappingcomponent.h index 9de0f49f1..38c4cdd9e 100644 --- a/src/blackgui/components/mappingcomponent.h +++ b/src/blackgui/components/mappingcomponent.h @@ -112,6 +112,9 @@ namespace BlackGui //! Reload models void ps_onMenuRequestModelReload(); + //! Highlight in simulator + void ps_onMenuHighlightInSimulator(const BlackMisc::Simulation::CSimulatedAircraft &aircraft); + private: static const QString &mappingtOriginator(); void updateSimulatedAircraftView(); diff --git a/src/blackgui/views/simulatedaircraftview.cpp b/src/blackgui/views/simulatedaircraftview.cpp index 6c10e5e65..089781051 100644 --- a/src/blackgui/views/simulatedaircraftview.cpp +++ b/src/blackgui/views/simulatedaircraftview.cpp @@ -32,6 +32,13 @@ namespace BlackGui this->setSortIndicator(); } + void CSimulatedAircraftView::configureMenu(bool menuHighlight, bool menuEnable, bool menufastPositionUpdates) + { + this->m_withMenuEnable = menuEnable; + this->m_withMenuFastPosition = menufastPositionUpdates; + this->m_withMenuHighlight = menuHighlight; + } + void CSimulatedAircraftView::customMenu(QMenu &menu) const { if (BlackMisc::CProject::isDebugBuild()) @@ -44,8 +51,9 @@ namespace BlackGui CSimulatedAircraft aircraft(selectedObject()); Q_ASSERT(!aircraft.getCallsign().isEmpty()); menu.addAction(CIcons::appTextMessages16(), "Show text messages", this, SLOT(ps_requestTextMessage())); - menu.addAction(CIcons::appAircrafts16(), aircraft.isEnabled() ? "Disable aircraft" : "Enabled aircraft", this, SLOT(ps_enableAircraft())); - menu.addAction(CIcons::globe16(), aircraft.fastPositionUpdates() ? "Normal updates" : "Fast position updates", this, SLOT(ps_fastPositionUpdates())); + if (m_withMenuEnable) { menu.addAction(CIcons::appAircrafts16(), aircraft.isEnabled() ? "Disable aircraft" : "Enabled aircraft", this, SLOT(ps_enableAircraft())); } + if (m_withMenuHighlight) { menu.addAction(CIcons::appSimulator16(), "Highlight in simulator", this, SLOT(ps_highlightInSimulator())); } + if (m_withMenuFastPosition) { menu.addAction(CIcons::globe16(), aircraft.fastPositionUpdates() ? "Normal updates" : "Fast position updates", this, SLOT(ps_fastPositionUpdates())); } menu.addSeparator(); } CViewBase::customMenu(menu); @@ -74,5 +82,12 @@ namespace BlackGui emit requestFastPositionUpdates(aircraft); } + void CSimulatedAircraftView::ps_highlightInSimulator() + { + CSimulatedAircraft aircraft(selectedObject()); + if (aircraft.getCallsign().isEmpty()) { return; } + emit requestHighlightInSimulator(aircraft); + } + } // ns } // ns diff --git a/src/blackgui/views/simulatedaircraftview.h b/src/blackgui/views/simulatedaircraftview.h index 061d898c8..b05221216 100644 --- a/src/blackgui/views/simulatedaircraftview.h +++ b/src/blackgui/views/simulatedaircraftview.h @@ -32,16 +32,22 @@ namespace BlackGui //! Mode void setAircraftMode(Models::CSimulatedAircraftListModel::AircraftMode mode); + //! configure the menu + void configureMenu(bool menuHighlight, bool menuEnable, bool menufastPositionUpdates); + signals: //! Request a text message void requestTextMessageWidget(const BlackMisc::Aviation::CCallsign &callsign); - //! Request enable / disable fast position updates + //! Request enable / disable fast position updates, \sa CSimulatedAircraft::fastPositionUpdates void requestFastPositionUpdates(const BlackMisc::Simulation::CSimulatedAircraft &aircraft); - //! Enable aircraft + //! Request to enable / disable aircraft, \sa CSimulatedAircraft::isEnabled void requestEnableAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraft); + //! Highlight given aircraft in simulator + void requestHighlightInSimulator(const BlackMisc::Simulation::CSimulatedAircraft &aircraft); + protected: //! \copydoc CViewBase::customMenu virtual void customMenu(QMenu &menu) const override; @@ -50,7 +56,12 @@ namespace BlackGui void ps_requestTextMessage(); void ps_enableAircraft(); void ps_fastPositionUpdates(); + void ps_highlightInSimulator(); + private: + bool m_withMenuHighlight = true; + bool m_withMenuEnable = true; + bool m_withMenuFastPosition = true; }; } // ns } // ns diff --git a/src/blackmisc/avaircraft.cpp b/src/blackmisc/avaircraft.cpp index b426f01b9..8ec616f56 100644 --- a/src/blackmisc/avaircraft.cpp +++ b/src/blackmisc/avaircraft.cpp @@ -90,6 +90,12 @@ namespace BlackMisc m_situation.setCallsign(this->getCallsign()); } + void CAircraft::setPilot(const Network::CUser &user) + { + m_pilot = user; + this->m_pilot.setCallsign(this->m_callsign); + } + const CComSystem CAircraft::getComSystem(CComSystem::ComUnit unit) const { switch (unit) @@ -150,12 +156,32 @@ namespace BlackMisc this->setTransponder(xpdr); } + CAircraftLights CAircraft::getLights() const + { + return m_parts.getLights(); + } + void CAircraft::setParts(const CAircraftParts &parts) { m_parts = parts; m_parts.setCallsign(this->getCallsign()); } + void CAircraft::setLights(CAircraftLights &lights) + { + m_parts.setLights(lights); + } + + void CAircraft::setAllLightsOn() + { + m_parts.setAllLightsOn(); + } + + void CAircraft::setAllLightsOff() + { + m_parts.setAllLightsOff(); + } + bool CAircraft::isVtol() const { return m_icao.isVtol(); diff --git a/src/blackmisc/avaircraft.h b/src/blackmisc/avaircraft.h index ab03f0456..da841ec82 100644 --- a/src/blackmisc/avaircraft.h +++ b/src/blackmisc/avaircraft.h @@ -84,7 +84,7 @@ namespace BlackMisc QString getPilotId() { return m_pilot.getId(); } //! Set pilot (user) - virtual void setPilot(const BlackMisc::Network::CUser &user) { m_pilot = user; this->m_pilot.setCallsign(this->m_callsign);} + virtual void setPilot(const BlackMisc::Network::CUser &user); //! Get ICAO info const CAircraftIcao &getIcaoInfo() const { return m_icao; } @@ -247,9 +247,21 @@ namespace BlackMisc //! Get aircraft parts const BlackMisc::Aviation::CAircraftParts &getParts() const { return m_parts; } + //! Get aircraft parts + CAircraftLights getLights() const; + //! Set aircraft parts void setParts(const BlackMisc::Aviation::CAircraftParts &parts); + //! Set aircraft lights + void setLights(BlackMisc::Aviation::CAircraftLights &lights); + + //! Set aircraft lights on + void setAllLightsOn(); + + //! Set aircraft lights off + void setAllLightsOff(); + //! VTOL aircraft? bool isVtol() const; diff --git a/src/blackmisc/aviation/aircraftlights.cpp b/src/blackmisc/aviation/aircraftlights.cpp index f0c57e414..e48b8923b 100644 --- a/src/blackmisc/aviation/aircraftlights.cpp +++ b/src/blackmisc/aviation/aircraftlights.cpp @@ -107,5 +107,25 @@ namespace BlackMisc } } + void CAircraftLights::setAllOn() + { + m_beaconOn = true; + m_landingOn = true; + m_logoOn = true; + m_navOn = true; + m_strobeOn = true; + m_taxiOn = true; + } + + void CAircraftLights::setAllOff() + { + m_beaconOn = false; + m_landingOn = false; + m_logoOn = false; + m_navOn = false; + m_strobeOn = false; + m_taxiOn = false; + } + } // namespace } // namespace diff --git a/src/blackmisc/aviation/aircraftlights.h b/src/blackmisc/aviation/aircraftlights.h index c6bea6114..91500e9e1 100644 --- a/src/blackmisc/aviation/aircraftlights.h +++ b/src/blackmisc/aviation/aircraftlights.h @@ -83,6 +83,12 @@ namespace BlackMisc //! Set logo lights void setLogoOn(bool on) { m_logoOn = on; } + //! All on + void setAllOn(); + + //! All off + void setAllOff(); + //! Returns object with all lights switched on static CAircraftLights allLightsOn(); diff --git a/src/blackmisc/aviation/aircraftparts.cpp b/src/blackmisc/aviation/aircraftparts.cpp index 395f1b197..8e2dc97e8 100644 --- a/src/blackmisc/aviation/aircraftparts.cpp +++ b/src/blackmisc/aviation/aircraftparts.cpp @@ -98,6 +98,16 @@ namespace BlackMisc } } + void CAircraftParts::setAllLightsOn() + { + m_lights.setAllOn(); + } + + void CAircraftParts::setAllLightsOff() + { + m_lights.setAllOff(); + } + CAircraftEngine CAircraftParts::getEngine(int number) const { return this->m_engines.getEngine(number); diff --git a/src/blackmisc/aviation/aircraftparts.h b/src/blackmisc/aviation/aircraftparts.h index 28994217f..77114268d 100644 --- a/src/blackmisc/aviation/aircraftparts.h +++ b/src/blackmisc/aviation/aircraftparts.h @@ -70,6 +70,12 @@ namespace BlackMisc //! Set aircraft lights void setLights(const CAircraftLights &lights) { m_lights = lights; } + //! Set all lights on + void setAllLightsOn(); + + //! Set all lights off + void setAllLightsOff(); + //! Is gear down? bool isGearDown() const { return m_gearDown; } diff --git a/src/blackmisc/simulation/simulatedaircraftlist.cpp b/src/blackmisc/simulation/simulatedaircraftlist.cpp index b9c83c97a..8df79a971 100644 --- a/src/blackmisc/simulation/simulatedaircraftlist.cpp +++ b/src/blackmisc/simulation/simulatedaircraftlist.cpp @@ -66,6 +66,60 @@ namespace BlackMisc return csl; } + void CSimulatedAircraftList::markAllAsNotRendered() + { + for (CSimulatedAircraft &aircraft : (*this)) + { + if (!aircraft.isRendered()) { continue; } + aircraft.setRendered(false); + } + } + + int CSimulatedAircraftList::setRendered(const CCallsign &callsign, bool rendered) + { + int c = 0; + for (CSimulatedAircraft &aircraft : (*this)) + { + if (aircraft.getCallsign() != callsign) { continue; } + aircraft.setRendered(rendered); + c++; + } + return c; + } + + int CSimulatedAircraftList::setAircraftParts(const CCallsign &callsign, const CAircraftParts &parts) + { + int c = 0; + for (CSimulatedAircraft &aircraft : (*this)) + { + if (aircraft.getCallsign() != callsign) { continue; } + aircraft.setParts(parts); + aircraft.setPartsSynchronized(true); + c++; + } + return c; + } + + bool CSimulatedAircraftList::isEnabled(const CCallsign &callsign) const + { + for (const CSimulatedAircraft &aircraft : (*this)) + { + if (aircraft.getCallsign() != callsign) { continue; } + return aircraft.isEnabled(); + } + return false; + } + + bool CSimulatedAircraftList::isRendered(const CCallsign &callsign) const + { + for (const CSimulatedAircraft &aircraft : (*this)) + { + if (aircraft.getCallsign() != callsign) { continue; } + return aircraft.isRendered(); + } + return false; + } + CAircraftList CSimulatedAircraftList::toAircraftList() const { CAircraftList al; diff --git a/src/blackmisc/simulation/simulatedaircraftlist.h b/src/blackmisc/simulation/simulatedaircraftlist.h index 85fd009df..28ae687ad 100644 --- a/src/blackmisc/simulation/simulatedaircraftlist.h +++ b/src/blackmisc/simulation/simulatedaircraftlist.h @@ -46,6 +46,21 @@ namespace BlackMisc //! Callsigns of aircraft with synchronized parts BlackMisc::Aviation::CCallsignList getCallsignsWithSyncronizedParts() const; + //! Mark all aircraft as unrendered + void markAllAsNotRendered(); + + //! Mark as rendered + int setRendered(const BlackMisc::Aviation::CCallsign &callsign, bool rendered); + + //! Set aircraft parts + int setAircraftParts(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftParts &parts); + + //! Enabled? + bool isEnabled(const BlackMisc::Aviation::CCallsign &callsign) const; + + //! Rendered? + bool isRendered(const BlackMisc::Aviation::CCallsign &callsign) const; + //! \copydoc CValueObject::toQVariant virtual QVariant toQVariant() const override { return QVariant::fromValue(*this); } diff --git a/src/plugins/simulator/fs9/fs9_client.cpp b/src/plugins/simulator/fs9/fs9_client.cpp index 24ad8a48f..2a0d7b517 100644 --- a/src/plugins/simulator/fs9/fs9_client.cpp +++ b/src/plugins/simulator/fs9/fs9_client.cpp @@ -85,7 +85,7 @@ namespace BlackSimPlugin CAircraftSituation situation = this->m_interpolator->getInterpolatedSituation(m_callsign, -1, status); // Test only for successful interpolation. FS9 requires constant positions - if (!status.interpolationSucceeded) return; + if (!status.interpolationSucceeded) { return; } sendMultiplayerPosition(situation); sendMultiplayerParamaters(); diff --git a/src/plugins/simulator/fs9/simulator_fs9.cpp b/src/plugins/simulator/fs9/simulator_fs9.cpp index 91efa5251..087a82de5 100644 --- a/src/plugins/simulator/fs9/simulator_fs9.cpp +++ b/src/plugins/simulator/fs9/simulator_fs9.cpp @@ -134,11 +134,20 @@ namespace BlackSimPlugin auto fs9Client = m_hashFs9Clients.value(callsign); fs9Client->quit(); m_hashFs9Clients.remove(callsign); - remoteAircraft().applyIfCallsign(callsign, CPropertyIndexVariantMap(CSimulatedAircraft::IndexRendered, CVariant::fromValue(false))); + remoteAircraft().setRendered(callsign, false); CLogMessage(this).info("FS9: Removed aircraft %1") << callsign.toQString(); return true; } + void CSimulatorFs9::removeAllRemoteAircraft() + { + QList callsigns(this->m_hashFs9Clients.keys()); + for (const CCallsign &cs : callsigns) + { + removeRemoteAircraft(cs); + } + } + bool CSimulatorFs9::updateOwnSimulatorCockpit(const CAircraft &ownAircraft, const QString &originator) { if (originator == this->simulatorOriginator()) { return false; } @@ -204,8 +213,14 @@ namespace BlackSimPlugin this->displayStatusMessage(message.asStatusMessage(true, true)); } - void CSimulatorFs9::timerEvent(QTimerEvent * /* event */) + bool CSimulatorFs9::isRenderedAircraft(const CCallsign &callsign) const { + return m_hashFs9Clients.contains(callsign); + } + + void CSimulatorFs9::timerEvent(QTimerEvent *event) + { + Q_UNUSED(event); ps_dispatch(); } diff --git a/src/plugins/simulator/fs9/simulator_fs9.h b/src/plugins/simulator/fs9/simulator_fs9.h index aca2b49ce..c8de192aa 100644 --- a/src/plugins/simulator/fs9/simulator_fs9.h +++ b/src/plugins/simulator/fs9/simulator_fs9.h @@ -42,9 +42,9 @@ namespace BlackSimPlugin public: //! \copydoc BlackCore::ISimulatorFactory::create(ownAircraftProvider, remoteAircraftProvider, parent) virtual BlackCore::ISimulator *create( - BlackMisc::Simulation::IOwnAircraftProvider *ownAircraftProvider, - BlackMisc::Simulation::IRemoteAircraftProvider *remoteAircraftProvider, - QObject *parent) override; + BlackMisc::Simulation::IOwnAircraftProvider *ownAircraftProvider, + BlackMisc::Simulation::IRemoteAircraftProvider *remoteAircraftProvider, + QObject *parent) override; //! Simulator info virtual BlackSim::CSimulatorInfo getSimulatorInfo() const override; @@ -91,6 +91,9 @@ namespace BlackSimPlugin //! \copydoc ISimulator::removeRemoteAircraft() virtual bool removeRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override; + //! \copydoc BlackCore::ISimulator::removeAllRemoteAircraft + virtual void removeAllRemoteAircraft() override; + //! \copydoc ISimulator::updateOwnSimulatorCockpit() virtual bool updateOwnSimulatorCockpit(const BlackMisc::Aviation::CAircraft &ownAircraft, const QString &originator) override; @@ -100,6 +103,9 @@ namespace BlackSimPlugin //! \copydoc ISimulator::displayTextMessage() virtual void displayTextMessage(const BlackMisc::Network::CTextMessage &message) const override; + //! \copydoc ISimulator::isRenderedAircraft + virtual bool isRenderedAircraft(const BlackMisc::Aviation::CCallsign &callsign) const override; + protected: //! Timer event virtual void timerEvent(QTimerEvent *event); @@ -124,12 +130,10 @@ namespace BlackSimPlugin // DirectPlay object handling QPointer m_fs9Host; - bool m_isHosting = false; //!< Is sim connected + bool m_isHosting = false; //!< Is sim connected? bool m_startedLobbyConnection = false; QHash> m_hashFs9Clients; CLobbyClient *m_lobbyClient; - - BlackCore::IInterpolator *m_interpolator = nullptr; //!< interpolator instance }; } // namespace } // namespace diff --git a/src/plugins/simulator/fscommon/simulator_fscommon.cpp b/src/plugins/simulator/fscommon/simulator_fscommon.cpp index 2ee7c719d..88102bc78 100644 --- a/src/plugins/simulator/fscommon/simulator_fscommon.cpp +++ b/src/plugins/simulator/fscommon/simulator_fscommon.cpp @@ -257,10 +257,10 @@ namespace BlackSimPlugin // remove upfront, and then enable / disable again this->removeRemoteAircraft(aircraft.getCallsign()); - return this->changeAircraftEnabled(aircraft, originator); + return this->changeRemoteAircraftEnabled(aircraft, originator); } - bool CSimulatorFsCommon::changeAircraftEnabled(const CSimulatedAircraft &aircraft, const QString &originator) + bool CSimulatorFsCommon::changeRemoteAircraftEnabled(const CSimulatedAircraft &aircraft, const QString &originator) { if (originator == simulatorOriginator()) { return false; } if (aircraft.isEnabled()) diff --git a/src/plugins/simulator/fscommon/simulator_fscommon.h b/src/plugins/simulator/fscommon/simulator_fscommon.h index 6ab858fd7..90d4f618c 100644 --- a/src/plugins/simulator/fscommon/simulator_fscommon.h +++ b/src/plugins/simulator/fscommon/simulator_fscommon.h @@ -75,7 +75,7 @@ namespace BlackSimPlugin virtual bool changeRemoteAircraftModel(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator) override; //! \copydoc ISimulator::changeAircraftEnabled - virtual bool changeAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator) override; + virtual bool changeRemoteAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator) override; //! \copydoc ISimulator::enableDebuggingMessages virtual void enableDebugMessages(bool driver, bool interpolator) override; @@ -95,7 +95,6 @@ namespace BlackSimPlugin bool m_simTimeSynced = false; //!< Time synchronized? BlackMisc::PhysicalQuantities::CTime m_syncTimeOffset; //!< time offset BlackMisc::Aviation::CAirportList m_airportsInRange; //!< aiports in range of own aircraft - BlackCore::IInterpolator *m_interpolator = nullptr; //!< interpolator instance // cockpit as set in SIM BlackMisc::Aviation::CComSystem m_simCom1; //!< cockpit COM1 state in simulator diff --git a/src/plugins/simulator/fsx/simulator_fsx.cpp b/src/plugins/simulator/fsx/simulator_fsx.cpp index 4160114f3..fcf409f6c 100644 --- a/src/plugins/simulator/fsx/simulator_fsx.cpp +++ b/src/plugins/simulator/fsx/simulator_fsx.cpp @@ -151,9 +151,9 @@ namespace BlackSimPlugin CLogMessage(this).warning("Have to remove aircraft %1 before I can add it") << callsign; } - SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxInitPosition(newRemoteAircraft.getSituation()); - initialPosition.Airspeed = 0; - initialPosition.OnGround = 0; + CSimulatedAircraft newRemoteAircraftCopy(newRemoteAircraft); + this->setInitialAircraftSituationAndParts(newRemoteAircraftCopy); + SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxInitPosition(newRemoteAircraftCopy.getSituation()); CSimConnectObject simObj; simObj.setCallsign(callsign); @@ -162,10 +162,11 @@ namespace BlackSimPlugin ++m_nextObjID; // matched models - CAircraftModel aircraftModel = modelMatching(newRemoteAircraft); + CAircraftModel aircraftModel = modelMatching(newRemoteAircraftCopy); Q_ASSERT(newRemoteAircraft.getCallsign() == aircraftModel.getCallsign()); - providerUpdateAircraftModel(newRemoteAircraft.getCallsign(), aircraftModel, simulatorOriginator()); + this->providerUpdateAircraftModel(newRemoteAircraft.getCallsign(), aircraftModel, simulatorOriginator()); CSimulatedAircraft aircraftAfterModelApplied = remoteAircraft().findFirstByCallsign(newRemoteAircraft.getCallsign()); + aircraftAfterModelApplied.setRendered(true); emit modelMatchingCompleted(aircraftAfterModelApplied); // create AI @@ -176,16 +177,15 @@ namespace BlackSimPlugin HRESULT hr = SimConnect_AICreateNonATCAircraft(m_hSimConnect, m.constData(), qPrintable(callsign.toQString().left(12)), initialPosition, simObj.getRequestId()); if (hr != S_OK) { CLogMessage(this).error("SimConnect, can not create AI traffic"); } m_simConnectObjects.insert(callsign, simObj); - remoteAircraft().applyIfCallsign(callsign, CPropertyIndexVariantMap(CSimulatedAircraft::IndexRendered, CVariant::fromValue(true))); CLogMessage(this).info("FSX: Added aircraft %1") << callsign.toQString(); return true; } else { - remoteAircraft().applyIfCallsign(callsign, CPropertyIndexVariantMap(CSimulatedAircraft::IndexRendered, CVariant::fromValue(false))); CLogMessage(this).warning("FSX: Not connected, not added aircraft %1") << callsign.toQString(); return false; } + remoteAircraft().setRendered(callsign, false); } bool CSimulatorFsx::updateOwnSimulatorCockpit(const CAircraft &ownAircraft, const QString &originator) @@ -294,6 +294,10 @@ namespace BlackSimPlugin this->displayStatusMessage(message.asStatusMessage(true, true)); } + bool CSimulatorFsx::isRenderedAircraft(const CCallsign &callsign) const + { + return this->m_simConnectObjects.contains(callsign); + } void CSimulatorFsx::onSimRunning() { @@ -510,11 +514,20 @@ namespace BlackSimPlugin return removeRemoteAircraft(m_simConnectObjects.value(callsign)); } + void CSimulatorFsx::removeAllRemoteAircraft() + { + QList callsigns(m_simConnectObjects.keys()); + for (const CCallsign &cs : callsigns) + { + removeRemoteAircraft(cs); + } + } + bool CSimulatorFsx::removeRemoteAircraft(const CSimConnectObject &simObject) { m_simConnectObjects.remove(simObject.getCallsign()); SimConnect_AIRemoveObject(m_hSimConnect, simObject.getObjectId(), simObject.getRequestId()); - remoteAircraft().applyIfCallsign(simObject.getCallsign(), CPropertyIndexVariantMap(CSimulatedAircraft::IndexRendered, CVariant::fromValue(false))); + remoteAircraft().setRendered(simObject.getCallsign(), false); CLogMessage(this).info("FSX: Removed aircraft %1") << simObject.getCallsign().toQString(); return true; } @@ -633,7 +646,7 @@ namespace BlackSimPlugin //! \todo The onGround in parts is nuts, as already mentioned in the discussion // a) I am forced to read parts even if i just want to update position - // b) Unlike the other values it is not a fire aforget value, as I need it again in the next cycle + // b) Unlike the other values it is not a fire and forget value, as I need it again in the next cycle if (partsStatus.supportsParts && !parts.isEmpty()) { // we have parts, and use the closest ground diff --git a/src/plugins/simulator/fsx/simulator_fsx.h b/src/plugins/simulator/fsx/simulator_fsx.h index 1a9282970..7f06b1ad2 100644 --- a/src/plugins/simulator/fsx/simulator_fsx.h +++ b/src/plugins/simulator/fsx/simulator_fsx.h @@ -110,6 +110,9 @@ namespace BlackSimPlugin //! \copydoc ISimulator::remoteRenderedAircraft() virtual bool removeRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override; + //! \copydoc BlackCore::ISimulator::removeAllRemoteAircraft + virtual void removeAllRemoteAircraft() override; + //! \copydoc ISimulator::updateOwnCockpit virtual bool updateOwnSimulatorCockpit(const BlackMisc::Aviation::CAircraft &ownAircraft, const QString &originator) override; @@ -119,6 +122,9 @@ namespace BlackSimPlugin //! \copydoc ISimulator::displayTextMessage() virtual void displayTextMessage(const BlackMisc::Network::CTextMessage &message) const override; + //! \copydoc ISimulator::isRenderedAircraft + virtual bool isRenderedAircraft(const BlackMisc::Aviation::CCallsign &callsign) const override; + //! Called when sim has started void onSimRunning(); @@ -141,11 +147,11 @@ namespace BlackSimPlugin void onSimExit(); protected: - //! Timer event + //! Timer event (our SimConnect event loop), runs \sa ps_dispatch + //! \sa m_simconnectTimerId virtual void timerEvent(QTimerEvent *event); private slots: - //! Dispatch SimConnect messages void ps_dispatch(); @@ -153,7 +159,6 @@ namespace BlackSimPlugin void ps_connectToFinished(); private: - //! Remove a remote aircraft bool removeRemoteAircraft(const CSimConnectObject &simObject); @@ -190,7 +195,6 @@ namespace BlackSimPlugin int m_interpolationsSkipped = 0; //!< number of skipped interpolation request HANDLE m_hSimConnect = nullptr; //!< Handle to SimConnect object uint m_nextObjID = 1; //!< object ID TODO: also used as request id, where to we place other request ids as for facilities - BlackMisc::PhysicalQuantities::CTime m_syncTimeOffset; //!< Time offset (if synchronized) QHash m_simConnectObjects; QFutureWatcher m_watcherConnect; diff --git a/src/plugins/simulator/xplane/simulator_xplane.cpp b/src/plugins/simulator/xplane/simulator_xplane.cpp index 72a2cb852..86e2d7bba 100644 --- a/src/plugins/simulator/xplane/simulator_xplane.cpp +++ b/src/plugins/simulator/xplane/simulator_xplane.cpp @@ -50,7 +50,8 @@ namespace BlackSimPlugin bool c = remoteAircraftProvider->connectRemoteAircraftProviderSignals( std::bind(&CSimulatorXPlane::ps_addAircraftSituation, this, std::placeholders::_1), std::bind(&CSimulatorXPlane::ps_addAircraftParts, this, std::placeholders::_1), - [](const BlackMisc::Aviation::CCallsign &) {}); + std::bind(&CSimulatorXPlane::ps_removedAircraft, this, std::placeholders::_1) + ); Q_ASSERT(c); Q_UNUSED(c); } @@ -313,6 +314,13 @@ namespace BlackSimPlugin return CPixmap(); } + bool CSimulatorXPlane::isRenderedAircraft(const CCallsign &callsign) const + { + //! \todo XP implement isRenderedAircraft correctly + // work around, but not really telling me if callsign is really(!) visible in SIM + return remoteAircraft().findFirstByCallsign(callsign).isRendered(); + } + bool CSimulatorXPlane::updateOwnSimulatorCockpit(const BlackMisc::Aviation::CAircraft &aircraft, const QString &originator) { if (originator == this->simulatorOriginator()) { return false; } @@ -375,18 +383,31 @@ namespace BlackSimPlugin m_traffic->setPlaneTransponder(parts.getCallsign().asString(), 2000, true, false); // TODO transponder } + void CSimulatorXPlane::ps_removedAircraft(const CCallsign &callsign) + { + Q_UNUSED(callsign); + //! \todo call removeRemoteAircraft or just let removeRemoteAircraft handle it? + } + bool CSimulatorXPlane::removeRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) { if (! isConnected()) { return false; } m_traffic->removePlane(callsign.asString()); - remoteAircraft().applyIfCallsign(callsign, CPropertyIndexVariantMap(CSimulatedAircraft::IndexRendered, CVariant::fromValue(false))); + remoteAircraft().setRendered(callsign, false); CLogMessage(this).info("XP: Removed aircraft %1") << callsign.toQString(); return true; } + void CSimulatorXPlane::removeAllRemoteAircraft() + { + m_traffic->removeAllPlanes(); + remoteAircraft().markAllAsNotRendered(); + CLogMessage(this).info("XP: Removed all aircraft"); + } + bool CSimulatorXPlane::changeRemoteAircraftModel(const CSimulatedAircraft &aircraft, const QString &originator) { - return this->changeAircraftEnabled(aircraft, originator); + return this->changeRemoteAircraftEnabled(aircraft, originator); } CAircraftIcao CSimulatorXPlane::getIcaoForModelString(const QString &modelString) const @@ -395,7 +416,7 @@ namespace BlackSimPlugin return CAircraftIcao(); } - bool CSimulatorXPlane::changeAircraftEnabled(const CSimulatedAircraft &aircraft, const QString &originator) + bool CSimulatorXPlane::changeRemoteAircraftEnabled(const CSimulatedAircraft &aircraft, const QString &originator) { if (originator == simulatorOriginator()) { return false; } if (aircraft.isEnabled()) diff --git a/src/plugins/simulator/xplane/simulator_xplane.h b/src/plugins/simulator/xplane/simulator_xplane.h index 74fa7f7f6..da98d97ce 100644 --- a/src/plugins/simulator/xplane/simulator_xplane.h +++ b/src/plugins/simulator/xplane/simulator_xplane.h @@ -74,11 +74,14 @@ namespace BlackSimPlugin //! \copydoc BlackCore::ISimulator::removeRemoteAircraft virtual bool removeRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override; + //! \copydoc BlackCore::ISimulator::removeAllRemoteAircraft + virtual void removeAllRemoteAircraft() override; + //! \copydoc ISimulator::changeRenderedAircraftModel virtual bool changeRemoteAircraftModel(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator) override; //! \copydoc ISimulator::changeAircraftEnabled - virtual bool changeAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator) override; + virtual bool changeRemoteAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const QString &originator) override; //! \copydoc BlackCore::ISimulator::updateOwnSimulatorCockpit virtual bool updateOwnSimulatorCockpit(const BlackMisc::Aviation::CAircraft &aircraft, const QString &originator) override; @@ -107,6 +110,9 @@ namespace BlackSimPlugin //! \copydoc ISimulator::iconForModel virtual BlackMisc::CPixmap iconForModel(const QString &modelString) const override; + //! \copydoc ISimulator::isRenderedAircraft + virtual bool isRenderedAircraft(const BlackMisc::Aviation::CCallsign &callsign) const override; + private slots: void ps_serviceRegistered(const QString &serviceName); void ps_serviceUnregistered(); @@ -117,6 +123,7 @@ namespace BlackSimPlugin void ps_addAircraftSituation(const BlackMisc::Aviation::CAircraftSituation &situ); void ps_addAircraftParts(const BlackMisc::Aviation::CAircraftParts &parts); + void ps_removedAircraft(const BlackMisc::Aviation::CCallsign &callsign); private: QDBusConnection m_conn { "default" };