// SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 //! \file #ifndef SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMULATORMSFS2024COMMON_H #define SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMULATORMSFS2024COMMON_H #include #include #include #include #include #include #include #include #include "config/buildconfig.h" #include "core/simulator.h" #include "gui/components/dbmappingcomponentaware.h" #include "misc/aviation/airportlist.h" #include "misc/aviation/altitude.h" #include "misc/datacache.h" #include "misc/network/client.h" #include "misc/pixmap.h" #include "misc/pq/frequency.h" #include "misc/simulation/aircraftmodel.h" #include "misc/simulation/data/modelcaches.h" // TODO ??? #include "misc/simulation/interpolation/interpolatorlinear.h" #include "misc/simulation/settings/modelmatchersettings.h" #include "misc/simulation/settings/simulatorsettings.h" #include "misc/simulation/simulatedaircraft.h" #include "misc/simulation/simulatorplugininfo.h" #include "misc/statusmessage.h" #include "plugins/simulator/fscommon/simulatorfscommon.h" #include "plugins/simulator/msfs2024/msfs2024export.h" #include "plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h" #include "plugins/simulator/msfs2024/simconnectobjectmsfs2024.h" #include "plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.h" #include "plugins/simulator/msfs2024/simconnectwindowsmsfs2024.h" namespace swift::simplugin::msfs2024common { //! SimConnect Event IDs enum EventIds { SystemEventSimStatus, SystemEventObjectAdded, SystemEventObjectRemoved, SystemEventSlewToggle, SystemEventFrame, SystemEventPause, SystemEventFlightLoaded, EventPauseToggle, EventFreezeLatLng, EventFreezeAlt, EventFreezeAtt, EventSetCom1Active, EventSetCom2Active, EventSetCom1Standby, EventSetCom2Standby, EventSetTransponderCode, EventTextMessage, EventSetTimeZuluYear, EventSetTimeZuluDay, EventSetTimeZuluHours, EventSetTimeZuluMinutes, // ------------ lights ------------- // EventLandingLightsOff, // EventLandinglightsOn, EventLandingLightsSet, // EventLandingLightsToggle, // EventPanelLightsOff, // EventPanelLightsOn, EventPanelLightsSet, // EventStrobesOff, // EventStrobesOn, EventStrobesSet, // EventStrobesToggle, EventBeaconLightsSet, EventCabinLightsSet, EventLogoLightsSet, EventNavLightsSet, EventRecognitionLightsSet, EventTaxiLightsSet, EventWingLightsSet, // ------------- flaps ------------- EventFlapsSet, EventGearSet, // ---------- end marker ----------- EventFSXEndMarker }; //! Struct to trace send ids struct TraceFsxSendId { //! Ctor TraceFsxSendId(DWORD sendId, const CSimConnectObject &simObject, const QString &comment) : sendId(sendId), simObject(simObject), comment(comment) {} // DWORD is unsigned DWORD sendId = 0; //!< the send id CSimConnectObject simObject; //!< CSimConnectObject at the time of the trace QString comment; //!< where sent //! For aircraft bool isForAircraft() const { return simObject.getType() == CSimConnectObject::AircraftNonAtc; } //! Invalid trace? bool isInvalid() const { return sendId == 0 && simObject.isInvalid() == 0 && comment.isEmpty(); } //! Valid trace? bool isValid() const { return !this->isInvalid(); } //! Invalid object static const TraceFsxSendId &invalid() { static const TraceFsxSendId i(0, CSimConnectObject(), ""); return i; } }; //! Buffer for models read from SimConnect struct sSimObjectLivery { QString szSimObjectCombinedTitle; QString szSimObjectTitle; QString szLiveryName; }; //! Flags for the load status of reading from the SimConnect struct sSimmobjectLoaded { bool bLoadStarted = false; bool bAirplaneLoaded = false; bool bHelicopterLoaded = false; bool bHotAirLoaded = false; }; //! FSX Simulator Implementation class MSFS2024_EXPORT CSimulatorMsfs2024 : public fscommon::CSimulatorFsCommon { Q_OBJECT Q_INTERFACES(swift::core::ISimulator) Q_INTERFACES(swift::misc::simulation::ISimulationEnvironmentProvider) Q_INTERFACES(swift::misc::simulation::IInterpolationSetupProvider) public: //! Constructor, parameters as in \sa swift::core::ISimulatorFactory::create CSimulatorMsfs2024(const swift::misc::simulation::CSimulatorPluginInfo &info, swift::misc::simulation::IOwnAircraftProvider *ownAircraftProvider, swift::misc::simulation::IRemoteAircraftProvider *remoteAircraftProvider, swift::misc::network::IClientProvider *clientProvider, QObject *parent = nullptr); //! Destructor virtual ~CSimulatorMsfs2024() override; //! \name ISimulator implementations //! @{ virtual bool connectTo() override; virtual bool disconnectFrom() override; virtual bool physicallyAddRemoteAircraft(const swift::misc::simulation::CSimulatedAircraft &newRemoteAircraft) override; virtual bool physicallyRemoveRemoteAircraft(const swift::misc::aviation::CCallsign &callsign) override; virtual int physicallyRemoveAllRemoteAircraft() override; virtual bool updateOwnSimulatorCockpit(const swift::misc::simulation::CSimulatedAircraft &ownAircraft, const swift::misc::CIdentifier &originator) override; virtual bool updateOwnSimulatorSelcal(const swift::misc::aviation::CSelcal &selcal, const swift::misc::CIdentifier &originator) override; virtual void displayStatusMessage(const swift::misc::CStatusMessage &message) const override; virtual void displayTextMessage(const swift::misc::network::CTextMessage &message) const override; virtual bool isPhysicallyRenderedAircraft(const swift::misc::aviation::CCallsign &callsign) const override; virtual swift::misc::aviation::CCallsignSet physicallyRenderedAircraft() const override; virtual swift::misc::CStatusMessageList debugVerifyStateAfterAllAircraftRemoved() const override; virtual QString getStatisticsSimulatorSpecific() const override; virtual void resetAircraftStatistics() override; virtual void setFlightNetworkConnected(bool connected) override; virtual swift::misc::CStatusMessageList getInterpolationMessages(const swift::misc::aviation::CCallsign &callsign) const override; virtual bool testSendSituationAndParts(const swift::misc::aviation::CCallsign &callsign, const swift::misc::aviation::CAircraftSituation &situation, const swift::misc::aviation::CAircraftParts &parts) override; //! @} ////! \copydoc swift::misc::simulation::ISimulationEnvironmentProvider::requestElevation ////! \remark x86 FSX version, x64 version is overridden ////! \sa CSimulatorFsxCommon::is // virtual bool requestElevation(const swift::misc::geo::ICoordinateGeodetic &reference, // const swift::misc::aviation::CCallsign &aircraftCallsign) override; //! saves the SimObjects received from the simulator a structure void CacheSimObjectAndLiveries(const SIMCONNECT_RECV_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST *msg); //! Write the sim objects and liveries to file and give back the number of objects written int writeSimObjectsAndLiveriesToFile(const swift::misc::simulation::CAircraftModelList Modelset); //! creates a new model list void createNewModelList(); //! resets the sim object and liveries cache void setSimObjectAndLiveries(); //! Tracing right now? bool isTracingSendId() const; //! Trace enable (can be auto enable also) bool isTraceSendId() const { return m_traceSendId; } //! Set tracing on/off void setTractingSendId(bool trace); //! Using the SB offsets? bool isUsingSbOffsetValues() const { return m_useSbOffsets; } //! Use SB offset values void setUsingSbOffsetValues(bool use); //! Number of received SB4 packets //! \remark if this is increasing, SB4 is supported int receivedSBPackets() const { return m_sbDataReceived; } //! Allow adding as simulated object instead of non ATC bool isAddingAsSimulatedObjectEnabled() const { return m_useAddSimulatedObj; } //! Allow adding as simulated object instead of non ATC void setAddingAsSimulatedObjectEnabled(bool enabled); //! Request for sim data (request in range of sim data)? static bool isRequestForSimObjAircraft(DWORD requestId) { return requestId >= RequestSimObjAircraftStart && requestId <= RequestSimObjAircraftRangeEnd; } //! Request for any CSimConnectObject? static bool isRequestForSimConnectObject(DWORD requestId) { return isRequestForSimObjAircraft(requestId); } //! Sub request type static CSimConnectDefinitions::SimObjectRequest requestToSimObjectRequest(DWORD requestId); //! Random unit text request id //! \private static DWORD unitTestRequestId(CSimConnectObject::SimObjectType type); //! Encapsulates creating QString from FSX string data static QString fsxCharToQString(const char *fsxChar, int size = -1); protected: //! SimConnect callback //! \note all tasks called in this function (i.e, all called functions) must perform fast or shall be called //! asynchronously static void CALLBACK SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext); //! \name Interface implementations //! @{ virtual bool isConnected() const override; virtual bool isSimulating() const override; //! @} //! \name Base class overrides //! @{ virtual void reset() override; virtual void initSimulatorInternals() override; virtual void clearAllRemoteAircraftData() override; virtual void onOwnModelChanged(const swift::misc::simulation::CAircraftModel &newModel) override; //! @} //! Timer event (our SimConnect event loop), runs dispatch //! \sa m_timerId //! \sa CSimulatorFsxCommon::dispatch virtual void timerEvent(QTimerEvent *event) override; //! Specific P3D events virtual HRESULT initEventsP3D(); //! \ingroup swiftdotcommands //!
        //! .drv sendid  on|off      tracing simConnect sendId on/off
        //! 
virtual bool parseDetails(const swift::misc::CSimpleCommandParser &parser) override; //! Trigger tracing ids for some while //! \sa CSimulatorFsxCommon::isTracingSendId bool triggerAutoTraceSendId(qint64 traceTimeMs = AutoTraceOffsetMs); //! Callsign for pending request swift::misc::aviation::CCallsign getCallsignForPendingProbeRequests(DWORD requestId, bool remove); //! Get new request id, overflow safe SIMCONNECT_DATA_REQUEST_ID obtainRequestIdForSimObjAircraft(); //! Release AI control //! \remark P3D version is overridden virtual bool releaseAIControl(const CSimConnectObject &simObject, SIMCONNECT_DATA_REQUEST_ID requestId); //! Valid CSimConnectObject which is NOT pendig removed bool isValidSimObjectNotPendingRemoved(const CSimConnectObject &simObject) const; //! CSimConnectObject for trace CSimConnectObject getSimObjectForTrace(const TraceFsxSendId &trace) const; //! Remove the CSimConnectObject linked in the trace bool removeSimObjectForTrace(const TraceFsxSendId &trace); //! Remove camera if any // virtual void removeCamera(CSimConnectObject &simObject); //! Remove observer if any // virtual void removeObserver(CSimConnectObject &simObject); //! Trace if required, log errors HRESULT logAndTraceSendId(HRESULT hr, const QString &warningMsg, const QString &functionName, const QString &functionDetails = {}); //! Trace if required, log errors HRESULT logAndTraceSendId(HRESULT hr, const CSimConnectObject &simObject, const QString &warningMsg, const QString &functionName, const QString &functionDetails = {}); //! Trace if required, log errors HRESULT logAndTraceSendId(HRESULT hr, bool traceSendId, const CSimConnectObject &simObject, const QString &warningMsg, const QString &functionName, const QString &functionDetails = {}); //! Convert to FSX char array static QByteArray toFsxChar(const QString &string); //! Register help static void registerHelp(); //! @{ //! Word size static bool is32bit() { return (swift::config::CBuildConfig::buildWordSize() == 32); } static bool is64bit() { return (swift::config::CBuildConfig::buildWordSize() == 64); } //! @} //! Format conversion //! \note must be valid situation static SIMCONNECT_DATA_INITPOSITION aircraftSituationToPosition(const swift::misc::aviation::CAircraftSituation &situation, bool sendGnd = true, bool forceUnderflowDetection = false, swift::misc::CStatusMessage *details = nullptr); //! Format conversion //! \note must be valid situation static SIMCONNECT_DATA_PBH aircraftSituationToFsxPBH(const swift::misc::aviation::CAircraftSituation &situation); //! Format conversion static SIMCONNECT_DATA_INITPOSITION coordinateToFsxPosition(const swift::misc::geo::ICoordinateGeodetic &coordinate); //! Format conversion static SIMCONNECT_DATA_LATLONALT coordinateToFsxLatLonAlt(const swift::misc::geo::ICoordinateGeodetic &coordinate); //! Valid FSX/P3D position static bool isValidFsxPosition(const SIMCONNECT_DATA_INITPOSITION &fsxPos); //! Valid 180degrees value static bool isValid180Deg(double deg) { return deg > -180.0 && deg <= 180.0; } static constexpr qint64 AutoTraceOffsetMs = 10 * 1000; //!< how long do we trace? HANDLE m_hSimConnect = nullptr; //!< handle to SimConnect object DispatchProc m_dispatchProc = &CSimulatorMsfs2024::SimConnectProc; //!< called function for dispatch, can be //!< overriden by specialized P3D function CSimConnectObjects m_simConnectObjects; //!< AI objects and their object and request ids QMap m_pendingProbeRequests; //!< pending elevation requests: requestId/aircraft callsign swift::misc::physical_quantities::CLength m_altitudeDelta; //!< FS2020 effect of temperature on altitude private: //! Reason for adding an aircraft enum AircraftAddMode { ExternalCall, //!< normal external request to add aircraft AddByTimer, //!< add pending aircraft by timer AddAfterAdded, //!< add pending because object successfully added AddedAfterRemoved //!< added again after removed }; //! Mode as string static const QString &modeToString(AircraftAddMode mode); //! Dispatch SimConnect messages //! \remark very frequently called void dispatch(); //! Implementation of add remote aircraft, which also handles FSX specific adding one by one //! \remark main purpose of this function is to only add one aircraft at a time, and only if simulator is not //! paused/stopped bool physicallyAddRemoteAircraftImpl(const swift::misc::simulation::CSimulatedAircraft &newRemoteAircraft, AircraftAddMode addMode, const CSimConnectObject &correspondingSimObject = {}); //! Remove aircraft no longer in provider //! \remark kind of cleanup function, in an ideal scenario this should never need to cleanup something swift::misc::aviation::CCallsignSet physicallyRemoveAircraftNotInProvider(); //! ASynchronous version of physicallyRemoveAircraftNotInProvider void physicallyRemoveAircraftNotInProviderAsync(); //! Verify that an object has been added in simulator //! \remark checks if the object was really added after an "add request" and not directly removed again //! \remark requests further data on remote aircraft (lights, ..) when correctly added void verifyAddedRemoteAircraft(const swift::misc::simulation::CSimulatedAircraft &remoteAircraftIn); //! Adding an aircraft failed void addingAircraftFailed(const CSimConnectObject &simObject); //! Create a detailed info about the failed aircraft bool verifyFailedAircraftInfo(const CSimConnectObject &simObject, swift::misc::CStatusMessage &details) const; //! Logging version of verifyFailedAircraftInfo bool logVerifyFailedAircraftInfo(const CSimConnectObject &simObject) const; //! Add next aircraft based on timer void timerBasedObjectAddOrRemove(); //! Add next aircraft after another has been confirmed void addPendingAircraftAfterAdded(); //! Try to add the next aircraft (one by one) void addPendingAircraft(AircraftAddMode mode); //! Remove as m_addPendingAircraft and m_aircraftToAddAgainWhenRemoved CSimConnectObject removeFromAddPendingAndAddAgainAircraft(const swift::misc::aviation::CCallsign &callsign); //! Call this method to declare the simulator connected void setSimConnected(); //! Called when simulator has started void onSimRunning(); //! Deferred version of onSimRunning to avoid jitter void onSimRunningDeferred(qint64 referenceTs); //! Called every visual frame void onSimFrame(); //! Called when simulator has stopped, e.g. by selecting the "select aircraft screen" void onSimStopped(); //! Simulator is going down void onSimExit(); //! Init when connected HRESULT initWhenConnected(); //! Initialize SimConnect system events HRESULT initEvents(); //! Initialize SimConnect data definitions HRESULT initDataDefinitionsWhenConnected(); //! Update remote aircraft //! \remark this is where the interpolated data are sent void updateRemoteAircraft(); //! Update remote aircraft parts (send to FSX) bool updateRemoteAircraftParts(const CSimConnectObject &simObject, const swift::misc::simulation::CInterpolationResult &result, bool forcedUpdate); //! Send parts to simulator //! \remark does not send if there is no change bool sendRemoteAircraftPartsToSimulator(const CSimConnectObject &simObject, const swift::misc::aviation::CAircraftParts &parts); //! Send ATC data (callsign etc.) to simulator bool sendRemoteAircraftAtcDataToSimulator(const CSimConnectObject &simObject); //! Call CSimulatorFsxCommon::updateRemoteAircraftFromSimulator asynchronously //! \remark do not to send SimConnect data in event loop void triggerUpdateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionPosData &remoteAircraftData); //! Call CSimulatorFsxCommon::updateRemoteAircraftFromSimulator asynchronously //! \remark do not to send SimConnect data in event loop void triggerUpdateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionRemoteAircraftModel &remoteAircraftModel); //! Remote aircraft data sent from simulator void updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionPosData &remoteAircraftData); //! Remote aircraft data sent from simulator void updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionRemoteAircraftModel &remoteAircraftModel); //! Probe data sent from simulator void updateProbeFromSimulator(const swift::misc::aviation::CCallsign &callsign, const DataDefinitionPosData &remoteAircraftData); //! Customization point for adjusting altitude to compensate for temperature effect virtual void setTrueAltitude(swift::misc::aviation::CAircraftSituation &aircraftSituation, const swift::simplugin::msfs2024common::DataDefinitionOwnAircraft &simulatorOwnAircraft); //! Called when data about our own aircraft are received void updateOwnAircraftFromSimulator(const DataDefinitionOwnAircraft &simulatorOwnAircraft); //! Update from SB client area //! \threadsafe void updateOwnAircraftFromSimulator(const DataDefinitionClientAreaSb &sbDataArea); //! Update transponder mode //! \threadsafe void updateTransponderMode(const misc::aviation::CTransponder::TransponderMode xpdrMode); //! Update transponder mode from MSFS void updateMSFS2024TransponderMode(const DataDefinitionMSFSTransponderMode transponderMode); //! An AI aircraft was added in the simulator bool simulatorReportedObjectAdded(DWORD objectId); //! Simulator reported that AI aircraft was removed bool simulatorReportedObjectRemoved(DWORD objectID); //! Set ID of a SimConnect object, so far we only have an request id in the object bool setSimConnectObjectId(DWORD requestId, DWORD objectId); //! Remember current lights bool setCurrentLights(const swift::misc::aviation::CCallsign &callsign, const swift::misc::aviation::CAircraftLights &lights); //! Remember lights sent bool setLightsAsSent(const swift::misc::aviation::CCallsign &callsign, const swift::misc::aviation::CAircraftLights &lights); //! Display receive exceptions? bool stillDisplayReceiveExceptions(); //! The SimConnect related objects const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; } //! The SimConnect object for idxs CSimConnectObject getSimObjectForObjectId(DWORD objectId) const; //! Request data for a CSimConnectObject (aka remote aircraft) bool requestPositionDataForSimObject(const CSimConnectObject &simObject, SIMCONNECT_PERIOD period = SIMCONNECT_PERIOD_SECOND); //! Request lights for a CSimConnectObject bool requestLightsForSimObject(const CSimConnectObject &simObject); //! Model info for a CSimConnectObject bool requestModelInfoForSimObject(const CSimConnectObject &simObject); //! Stop requesting data for CSimConnectObject bool stopRequestingDataForSimObject(const CSimConnectObject &simObject); //! FSX position as string static QString fsxPositionToString(const SIMCONNECT_DATA_INITPOSITION &position); //! Get the callsigns which are no longer in the provider, but still in m_simConnectObjects swift::misc::aviation::CCallsignSet getCallsignsMissingInProvider() const; //! Set tracing on/off void setTraceSendId(bool traceSendId) { m_traceSendId = traceSendId; } //! Trace the send id void traceSendId(const CSimConnectObject &simObject, const QString &functionName, const QString &details = {}, bool forceTrace = false); //! Send id trace or given send id TraceFsxSendId getSendIdTrace(DWORD sendId) const; //! Get the trace details, otherwise empty string QString getSendIdTraceDetails(const TraceFsxSendId &trace) const; //! Get the trace details, otherwise empty string QString getSendIdTraceDetails(DWORD sendId) const; //! Remove all probes int removeAllProbes(); //! Insert a new SimConnect object CSimConnectObject insertNewSimConnectObject(const swift::misc::simulation::CSimulatedAircraft &aircraft, DWORD requestId, CSimConnectObject::SimObjectType type, const CSimConnectObject &removedPendingObject = {}); //! Update simulator COM from swift data. Returns true if simulator frequency was changed bool updateCOMFromSwiftToSimulator(const swift::misc::physical_quantities::CFrequency &newFreq, const swift::misc::physical_quantities::CFrequency &lastSimFreq, swift::misc::physical_quantities::CFrequency &last25kHzSimFreq, EventIds id); //! Used for terrain probes static const swift::misc::aviation::CAltitude &terrainProbeAltitude(); static constexpr int GuessRemoteAircraftPartsCycle = 20; //!< guess every n-th cycle static constexpr int SkipUpdateCyclesForCockpit = 10; //!< skip x cycles before updating cockpit again static constexpr int IgnoreReceiveExceptions = 10; //!< skip exceptions when displayed more than x times static constexpr int MaxSendIdTraces = 10000; //!< max.traces of send id static constexpr DWORD MaxSimObjAircraft = 10000; //!< max.number of SimObjects at the same time static constexpr DWORD MaxSimObjProbes = 100; //!< max. probes // -- second chance tresholds -- static constexpr int ThresholdAddException = 1; //!< one failure allowed static constexpr int ThresholdAddedAndDirectlyRemoved = 2; //!< two failures allowed // -- range for sim data, each sim object will get its own request id and use the offset ranges static constexpr int RequestSimObjAircraftStart = static_cast(CSimConnectDefinitions::RequestEndMarker); static constexpr int RequestSimObjAircraftEnd = RequestSimObjAircraftStart - 1 + MaxSimObjAircraft; static constexpr int RequestSimObjAircraftRangeEnd = RequestSimObjAircraftStart - 1 + static_cast(CSimConnectDefinitions::SimObjectEndMarker) * MaxSimObjAircraft; // times static constexpr int AddPendingAircraftIntervalMs = 10 * 1000; static constexpr int DispatchIntervalMs = 10; //!< how often with run the FSX event queue static constexpr int DeferSimulatingFlagMs = 1500; //!< simulating can jitter at startup (simulating->stopped->simulating, multiple start events), so we //!< defer detection static constexpr int DeferResendingLights = 2500; //!< Resend light state when aircraft light state was not yet available QString m_simConnectVersion; //!< SimConnect version bool m_simConnected = false; //!< Is simulator connected? bool m_simSimulating = false; //!< Simulator running? bool m_useSbOffsets = true; //!< with SB offsets bool m_logSbOffsets = false; //!< log SB offsets bool m_traceSendId = false; //!< trace the send ids, meant for debugging bool m_useAddSimulatedObj = false; //!< simulated object use if AI Non ATC object fails qint64 m_traceAutoUntilTs = -1; //!< allows to automatically trace for some time qint64 m_simulatingChangedTs = -1; //!< timestamp, when simulating changed (used to avoid jitter) int m_sbDataReceived = 0; //!< SB3 area data received // tracing dispatch performance int m_dispatchErrors = 0; //!< number of dispatched failed, \sa dispatch int m_dispatchProcCount = 0; //!< number of dispatchProc counts int m_dispatchProcEmptyCount = 0; //!< number dispatchProc doing nothing qint64 m_dispatchTimeMs = -1; //!< \sa ISimulator::getStatisticsSimulatorSpecific qint64 m_dispatchMaxTimeMs = -1; //!< \sa ISimulator::getStatisticsSimulatorSpecific qint64 m_dispatchProcTimeMs = -1; //!< \sa ISimulator::getStatisticsSimulatorSpecific qint64 m_dispatchProcMaxTimeMs = -1; //!< \sa ISimulator::getStatisticsSimulatorSpecific SIMCONNECT_RECV_ID m_dispatchReceiveIdLast = SIMCONNECT_RECV_ID_NULL; //!< last receive id from dispatching SIMCONNECT_RECV_ID m_dispatchReceiveIdMaxTime = SIMCONNECT_RECV_ID_NULL; //!< receive id corresponding to max.time DWORD m_dispatchRequestIdLast = CSimConnectDefinitions::RequestEndMarker; //!< request id if any for last request DWORD m_dispatchRequestIdMaxTime = CSimConnectDefinitions::RequestEndMarker; //!< request id corresponding to max.time // sending via SimConnect QList m_sendIdTraces; //!< Send id traces for debugging, latest first int m_receiveExceptionCount = 0; //!< exceptions int m_requestSimObjectDataCount = 0; //!< requested SimObjects // settings swift::misc::simulation::settings::CMultiSimulatorDetailsSettings m_detailsSettings; // objects CSimConnectObjects m_simConnectObjectsPositionAndPartsTraces; //!< position/parts received, but object not yet //!< added, excluded, disabled etc. CSimConnectObjects m_addPendingAircraft; //!< aircraft/probes awaiting to be added; SIMCONNECT_DATA_REQUEST_ID m_requestIdSimObjAircraft = static_cast( RequestSimObjAircraftStart); //!< request id, use obtainRequestIdForSimObjAircraft to get id QTimer m_simObjectTimer; //!< updating of SimObjects awaiting to be added // Last selected frequencies in simulator before setting 8.33 kHz spacing frequency swift::misc::physical_quantities::CFrequency m_lastCom1Active { 0, swift::misc::physical_quantities::CFrequencyUnit::nullUnit() }; //!< last COM1 active frequency swift::misc::physical_quantities::CFrequency m_lastCom1Standby { 0, swift::misc::physical_quantities::CFrequencyUnit::nullUnit() }; //!< last COM1 standby frequency swift::misc::physical_quantities::CFrequency m_lastCom2Active { 0, swift::misc::physical_quantities::CFrequencyUnit::nullUnit() }; //!< last COM2 active frequency swift::misc::physical_quantities::CFrequency m_lastCom2Standby { 0, swift::misc::physical_quantities::CFrequencyUnit::nullUnit() }; //!< last COM2 standby frequency //! Request id to string static QString requestIdToString(DWORD requestId); //! status of loaded sim objects sSimmobjectLoaded sSimmobjectLoadedState; //! cached sim objects and liveries read frim simconnect std::vector vSimObjectsAndLiveries; //! Simulator info swift::misc::simulation::CSimulatorInfo m_simulatorInfo; swift::misc::CSetting m_matchingSettings { this }; //!< settings public: //! @{ //! Offsets static DWORD offsetSimObjAircraft(CSimConnectDefinitions::SimObjectRequest req) { return MaxSimObjAircraft * static_cast(req); } //! @} }; //! Listener for MSFS2024 class MSFS2024_EXPORT CSimulatorMsfs2024Listener : public swift::core::ISimulatorListener { Q_OBJECT public: //! Constructor CSimulatorMsfs2024Listener(const swift::misc::simulation::CSimulatorPluginInfo &info); //! \copydoc swift::core::ISimulatorListener::backendInfo virtual QString backendInfo() const override; protected: //! \copydoc swift::core::ISimulatorListener::startImpl virtual void startImpl() override; //! \copydoc swift::core::ISimulatorListener::stopImpl virtual void stopImpl() override; //! \copydoc swift::core::ISimulatorListener::checkImpl virtual void checkImpl() override; private: //! Test if connection can be established void checkConnection(); //! Check simulator version and type bool checkVersionAndSimulator() const; //! Check the simconnect.dll bool checkSimConnectDll() const; //! Connect to simulator (if not already) bool connectToSimulator(); //! Disconnect from simulator bool disconnectFromSimulator(); //! Adjust the timer interval void adjustTimerInterval(qint64 checkTimeMs); static constexpr int MinQueryIntervalMs = 5 * 1000; // 5 seconds QTimer m_timer { this }; //!< timer, "this" is needed otherwise I get warnings when move to new thread QString m_simulatorVersion; QString m_simConnectVersion; QString m_simulatorName; QString m_simulatorDetails; HANDLE m_hSimConnect; bool m_simConnected = false; //!< SimConnect is connected, does not mean to the correct sim. swift::misc::CStatusMessage m_lastMessage; //!< last listener message //! SimConnect Callback (simplified version for listener) //! \sa CSimConnectObjects::SimConnectProc static void CALLBACK SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext); }; } // namespace swift::simplugin::msfs2024common #endif // SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMULATORMSFS2024COMMON_H