diff --git a/src/plugins/simulator/fscommon/simulatorfscommon.h b/src/plugins/simulator/fscommon/simulatorfscommon.h index c03b41a99..b58eb0a2d 100644 --- a/src/plugins/simulator/fscommon/simulatorfscommon.h +++ b/src/plugins/simulator/fscommon/simulatorfscommon.h @@ -54,6 +54,9 @@ namespace swift::simplugin::fscommon 0; //!< own aircraft updates, even with 50 updates/sec long enough even for 32bit int m_skipCockpitUpdateCycles = 0; //!< skip some update cycles to allow changes in simulator cockpit to be set bool m_simPaused = false; //!< simulator paused? + bool m_simTimeSynced = false; //!< time synchronized? + swift::misc::physical_quantities::CTime m_syncTimeOffset; //!< time offset + swift::misc::aviation::CAirportList m_airportsInRangeFromSimulator; //!< airports in range of own aircraft // cockpit as set in SIM swift::misc::aviation::CComSystem m_simCom1; //!< cockpit COM1 state in simulator diff --git a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h index 642b62479..140bbe257 100644 --- a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h +++ b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h @@ -209,6 +209,15 @@ namespace swift::simplugin::fsxcommon bool isOnGround() const { return this->aboveGroundFt() < 1.0; } }; + //! Data struct simulator environment + struct DataDefinitionSimEnvironment + { + qint32 zuluTimeSeconds; //!< Simulator zulu (GMT) time in secs. + qint32 zuluYear; //!< Simulator zulu (GMT) year. + qint32 zuluMonth; //!< Simulator zulu (GMT) month. + qint32 zuluDayOfMonth; //!< Simulator zulu (GMT) day of the month. + }; + //! The whole SB data area //! \remark vPilot SB area https://forums.vatsim.net/viewtopic.php?p=519580 //! \remark SB offsets http://www.squawkbox.ca/doc/sdk/fsuipc.php @@ -291,6 +300,7 @@ namespace swift::simplugin::fsxcommon { RequestOwnAircraft, RequestOwnAircraftTitle, + RequestSimEnvironment, RequestSbData, //!< SB client area / XPDR mode RequestMSFSTransponder, //!< MSFS XPDR mode/ident RequestFacility, diff --git a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp index 5eb82a438..113a8b6c5 100644 --- a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp +++ b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp @@ -527,7 +527,14 @@ namespace swift::simplugin::fsxcommon SIMCONNECT_PERIOD_SECOND, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED), "Cannot request title", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); - if (!this->getSimulatorPluginInfo().getSimulatorInfo().isMSFS()) + hr += this->logAndTraceSendId( + SimConnect_RequestDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::RequestSimEnvironment, + CSimConnectDefinitions::DataSimEnvironment, SIMCONNECT_OBJECT_ID_USER, + SIMCONNECT_PERIOD_SECOND, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED), + "Cannot request sim.env.", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); + + if (!this->getSimulatorPluginInfo().getSimulatorInfo().isMSFS() && + !this->getSimulatorPluginInfo().getSimulatorInfo().isMSFS2024()) { // Request the data from SB only when its changed and only ONCE so we don't have to run a 1sec event to // get/set this info ;) there was a bug with SIMCONNECT_CLIENT_DATA_PERIOD_ON_SET, see @@ -2208,6 +2215,39 @@ namespace swift::simplugin::fsxcommon return ok; } + void CSimulatorFsxCommon::triggerUpdateAirports(const CAirportList &airports) + { + if (this->isShuttingDownOrDisconnected()) { return; } + if (airports.isEmpty()) { return; } + QPointer myself(this); + QTimer::singleShot(0, this, [=] { + if (!myself) { return; } + this->updateAirports(airports); + }); + } + + void CSimulatorFsxCommon::updateAirports(const CAirportList &airports) + { + if (airports.isEmpty()) { return; } + + static const CLength maxDistance(200.0, CLengthUnit::NM()); + const CCoordinateGeodetic posAircraft(this->getOwnAircraftPosition()); + + for (const CAirport &airport : airports) + { + CAirport consolidatedAirport(airport); + const CLength d = consolidatedAirport.calculcateAndUpdateRelativeDistanceAndBearing(posAircraft); + if (d > maxDistance) { continue; } + // consolidatedAirport.updateMissingParts(this->getWebServiceAirport(airport.getIcao())); + // m_airportsInRangeFromSimulator.replaceOrAddByIcao(consolidatedAirport); + // if (m_airportsInRangeFromSimulator.size() > this->maxAirportsInRange()) + //{ + // m_airportsInRangeFromSimulator.sortByDistanceToReferencePosition(); + // m_airportsInRangeFromSimulator.truncate(this->maxAirportsInRange()); + // } + } + } + bool CSimulatorFsxCommon::sendRemoteAircraftPartsToSimulator(const CSimConnectObject &simObject, const CAircraftParts &parts) { @@ -2511,6 +2551,61 @@ namespace swift::simplugin::fsxcommon return true; } + void CSimulatorFsxCommon::synchronizeTime(const DataDefinitionSimEnvironment *simEnv) + { + if (!m_simTimeSynced) { return; } + if (!this->isConnected()) { return; } + if (m_syncTimeDeferredCounter > 0) + { + --m_syncTimeDeferredCounter; + return; // wait some time before we snyc again + } + + const int zh = simEnv->zuluTimeSeconds / 3600; + const int zm = (simEnv->zuluTimeSeconds - (zh * 3600)) / 60; + const QDateTime simDateTime({ simEnv->zuluYear, simEnv->zuluMonth, simEnv->zuluDayOfMonth }, { zh, zm }, + Qt::UTC); + + QDateTime currentDateTime = QDateTime::currentDateTimeUtc(); + if (!m_syncTimeOffset.isZeroEpsilonConsidered()) + { + int offsetSeconds = m_syncTimeOffset.valueInteger(CTimeUnit::s()); + currentDateTime = currentDateTime.addSecs(offsetSeconds); + } + + if (qAbs(simDateTime.secsTo(currentDateTime)) < 120) + { + // checked and no relevant difference + m_syncTimeDeferredCounter = 10; // wait some time to check again + return; + } + + const DWORD h = static_cast(currentDateTime.time().hour()); + const DWORD m = static_cast(currentDateTime.time().minute()); + const DWORD y = static_cast(currentDateTime.date().year()); + const DWORD d = static_cast(currentDateTime.date().dayOfYear()); + + const HRESULT hr1 = SimConnect_TransmitClientEvent(m_hSimConnect, 0, EventSetTimeZuluHours, h, + SIMCONNECT_GROUP_PRIORITY_STANDARD, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY); + const HRESULT hr2 = SimConnect_TransmitClientEvent(m_hSimConnect, 0, EventSetTimeZuluMinutes, m, + SIMCONNECT_GROUP_PRIORITY_STANDARD, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY); + const HRESULT hr3 = SimConnect_TransmitClientEvent(m_hSimConnect, 0, EventSetTimeZuluYear, y, + SIMCONNECT_GROUP_PRIORITY_STANDARD, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY); + const HRESULT hr4 = + SimConnect_TransmitClientEvent(m_hSimConnect, 0, EventSetTimeZuluDay, d, SIMCONNECT_GROUP_PRIORITY_STANDARD, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY); + + if (isFailure(hr1, hr2, hr3, hr4)) { CLogMessage(this).warning(u"Sending time sync failed!"); } + else + { + m_syncTimeDeferredCounter = 5; // allow some time to sync + CLogMessage(this).info(u"Synchronized time to '%1' UTC") << currentDateTime.toString(); + } + } + bool CSimulatorFsxCommon::requestPositionDataForSimObject(const CSimConnectObject &simObject, SIMCONNECT_PERIOD period) { @@ -2630,6 +2725,7 @@ namespace swift::simplugin::fsxcommon m_simConnected = false; m_simSimulating = false; m_sbDataReceived = 0; + m_syncTimeDeferredCounter = 0; m_requestIdSimObjAircraft = static_cast(RequestSimObjAircraftStart); m_dispatchErrors = 0; m_receiveExceptionCount = 0; @@ -3013,6 +3109,16 @@ namespace swift::simplugin::fsxcommon return connectedSimName.contains("fsx") || connectedSimName.contains("microsoft") || connectedSimName.contains("simulator x"); } + else if (pluginSim.isMSFS()) + { + // MSFS 2020 drivers only works with MSFS + return connectedSimName.contains("kittyhawk"); + } + else if (pluginSim.isMSFS2024()) + { + // MSFS2024 drivers only works with MSFS2024 + return connectedSimName.contains("sunrise"); + } return false; } diff --git a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.h b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.h index 5cb1976eb..56d40ccf3 100644 --- a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.h +++ b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.h @@ -461,6 +461,12 @@ namespace swift::simplugin::fsxcommon bool updateRemoteAircraftParts(const CSimConnectObject &simObject, const swift::misc::simulation::CInterpolationResult &result, bool forcedUpdate); + //! Calling CSimulatorFsxCommon::updateAirports + void triggerUpdateAirports(const swift::misc::aviation::CAirportList &airports); + + //! Update airports from simulator + void updateAirports(const swift::misc::aviation::CAirportList &airports); + //! Send parts to simulator //! \remark does not send if there is no change bool sendRemoteAircraftPartsToSimulator(const CSimConnectObject &simObject, @@ -543,6 +549,9 @@ namespace swift::simplugin::fsxcommon //! The SimConnect object for idxs CSimConnectObject getSimObjectForObjectId(DWORD objectId) const; + //! Sync time with user's computer + void synchronizeTime(const DataDefinitionSimEnvironment *simEnv); + //! Request data for a CSimConnectObject (aka remote aircraft) bool requestPositionDataForSimObject(const CSimConnectObject &simObject, SIMCONNECT_PERIOD period = SIMCONNECT_PERIOD_SECOND); @@ -642,6 +651,7 @@ namespace swift::simplugin::fsxcommon 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 + int m_syncTimeDeferredCounter = 0; //!< Set when synchronized, used to wait some time // tracing dispatch performance int m_dispatchErrors = 0; //!< number of dispatched failed, \sa dispatch diff --git a/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp b/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp index 68643c4aa..fa4dd7c25 100644 --- a/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp +++ b/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp @@ -260,6 +260,13 @@ namespace swift::simplugin::fsxcommon simulatorFsxP3D->reverseLookupAndUpdateOwnAircraftModel(model); break; } + case CSimConnectDefinitions::RequestSimEnvironment: + { + const DataDefinitionSimEnvironment *simEnv = + reinterpret_cast(&pObjData->dwData); + simulatorFsxP3D->synchronizeTime(simEnv); + break; + } case CSimConnectDefinitions::RequestMSFSTransponder: { const DataDefinitionMSFSTransponderMode *transponderMode = @@ -368,6 +375,32 @@ namespace swift::simplugin::fsxcommon } break; // SIMCONNECT_RECV_ID_SIMOBJECT_DATA } + case SIMCONNECT_RECV_ID_AIRPORT_LIST: + { + const SIMCONNECT_RECV_AIRPORT_LIST *pAirportList = static_cast(pData); + CAirportList simAirports; + for (unsigned i = 0; i < pAirportList->dwArraySize; ++i) + { + const SIMCONNECT_DATA_FACILITY_AIRPORT *pFacilityAirport = pAirportList->rgData + i; + if (!pFacilityAirport) { break; } + const QString icao(pFacilityAirport->Icao); + if (icao.isEmpty()) { continue; } // airfield without ICAO code + if (!CAirportIcaoCode::isValidIcaoDesignator(icao, true)) + { + continue; + } // tiny airfields/strips in simulator + if (CAirportIcaoCode::containsNumbers(icao)) { continue; } // tiny airfields/strips in simulator + const CCoordinateGeodetic pos(pFacilityAirport->Latitude, pFacilityAirport->Longitude, + pFacilityAirport->Altitude); + const CAirport airport(CAirportIcaoCode(icao), pos); + simAirports.push_back(airport); + } + if (!simAirports.isEmpty()) + { + // simulatorFsxP3D->triggerUpdateAirports(simAirports); // real "work" outside SimConnectProc + } + break; // SIMCONNECT_RECV_ID_AIRPORT_LIST + } case SIMCONNECT_RECV_ID_CLIENT_DATA: { if (!simulatorFsxP3D->m_useSbOffsets) { break; } diff --git a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h index c1d1e730e..56479a13d 100644 --- a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h +++ b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h @@ -310,6 +310,7 @@ namespace swift::simplugin::msfs2024common RequestOwnAircraft, RequestOwnAircraftTitle, RequestOwnAircraftLivery, + RequestSimEnvironment, RequestSbData, //!< SB client area / XPDR mode RequestMSFSTransponder, //!< MSFS XPDR mode/ident RequestFacility, diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp index e7e8812d0..e7de387ac 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp @@ -759,6 +759,12 @@ namespace swift::simplugin::msfs2024common SIMCONNECT_SIMOBJECT_TYPE_USER), "Cannot request title and livery", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObjectType"); + hr += this->logAndTraceSendId( + SimConnect_RequestDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::RequestSimEnvironment, + CSimConnectDefinitions::DataSimEnvironment, SIMCONNECT_OBJECT_ID_USER, + SIMCONNECT_PERIOD_SECOND, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED), + "Cannot request sim.env.", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); + hr += this->logAndTraceSendId(SimConnect_RequestDataOnSimObject( m_hSimConnect, CSimConnectDefinitions::RequestMSFSTransponder, CSimConnectDefinitions::DataTransponderModeMSFS, SIMCONNECT_OBJECT_ID_USER,