From 53d069a5d10ec079d21ee6dc76c4397fc20a940d Mon Sep 17 00:00:00 2001 From: tzobler Date: Tue, 14 Oct 2025 10:47:13 +0200 Subject: [PATCH 1/8] feat: new method for loading models via SimConnect MSFS2024 --- .github/workflows/build.yml | 4 +- .gitignore | 2 + src/core/db/databaseutils.cpp | 4 + src/core/modelsetbuilder.cpp | 5 +- src/core/modelsetbuilder.h | 3 +- src/gui/components/dbownmodelscomponent.cpp | 25 +- src/gui/components/dbownmodelscomponent.h | 9 +- src/gui/components/mappingcomponent.ui | 705 ++-- .../settingssimulatorbasicscomponent.cpp | 118 +- .../settingssimulatorbasicscomponent.ui | 457 ++- src/gui/editors/ownmodelsetform.ui | 6 +- src/gui/models/aircraftmodellistmodel.cpp | 10 +- src/misc/CMakeLists.txt | 2 + src/misc/simulation/aircraftmodel.cpp | 38 + src/misc/simulation/aircraftmodel.h | 30 +- src/misc/simulation/aircraftmodellist.cpp | 30 +- src/misc/simulation/aircraftmodellist.h | 6 +- src/misc/simulation/aircraftmodelloader.cpp | 26 +- .../aircraftmodelloaderprovider.cpp | 3 + src/misc/simulation/aircraftmodelutils.cpp | 14 +- .../simulation/fscommon/aircraftcfgparser.cpp | 11 +- .../simulation/fscommon/aircraftcfgparser.h | 2 +- src/misc/simulation/fscommon/fscommonutil.cpp | 11 - src/misc/simulation/fscommon/fscommonutil.h | 9 - .../simulation/fscommon/fsdirectories.cpp | 6 +- .../msfs2024/aircraftmodelloadermsfs2024.cpp | 107 + .../msfs2024/aircraftmodelloadermsfs2024.h | 44 + .../simulation/settings/simulatorsettings.cpp | 17 +- .../simulation/settings/simulatorsettings.h | 21 +- src/misc/simulation/simulatedaircraft.h | 6 + src/plugins/simulator/CMakeLists.txt | 2 +- .../fsxcommon/simconnectdatadefinition.cpp | 32 +- .../fsxcommon/simconnectdatadefinition.h | 3 +- .../simulator/fsxcommon/simconnectsymbols.cpp | 31 - .../simulator/fsxcommon/simconnectsymbols.h | 2 +- .../simulator/fsxcommon/simconnectwindows.h | 4 +- .../fsxcommon/simulatorfsxcommon.cpp | 1 - src/plugins/simulator/msfs2024/CMakeLists.txt | 14 +- .../simulator/msfs2024/msfs2024export.h | 26 + .../simconnectdatadefinitionmsfs2024.cpp | 556 +++ .../simconnectdatadefinitionmsfs2024.h | 383 ++ .../msfs2024/simconnectobjectmsfs2024.cpp | 547 +++ .../msfs2024/simconnectobjectmsfs2024.h | 450 +++ .../msfs2024/simconnectsymbolsmsfs2024.cpp | 585 +++ .../msfs2024/simconnectsymbolsmsfs2024.h | 15 + .../msfs2024/simconnectwindowsmsfs2024.h | 28 + .../simulator/msfs2024/simulatormsfs2024.cpp | 12 +- .../simulator/msfs2024/simulatormsfs2024.h | 16 +- .../msfs2024/simulatormsfs2024common.cpp | 3331 +++++++++++++++++ .../msfs2024/simulatormsfs2024common.h | 817 ++++ .../simulatormsfs2024simconnectproc.cpp | 464 +++ src/swiftdata/CMakeLists.txt | 2 + src/swiftdata/main.cpp | 31 +- src/swiftdata/swiftdata.h | 3 +- src/swiftdata/swiftdataapplication.cpp | 106 + src/swiftdata/swiftdataapplication.h | 48 + 56 files changed, 8526 insertions(+), 714 deletions(-) create mode 100644 src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp create mode 100644 src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.h create mode 100644 src/plugins/simulator/msfs2024/msfs2024export.h create mode 100644 src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp create mode 100644 src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h create mode 100644 src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.cpp create mode 100644 src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.h create mode 100644 src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.cpp create mode 100644 src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.h create mode 100644 src/plugins/simulator/msfs2024/simconnectwindowsmsfs2024.h create mode 100644 src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp create mode 100644 src/plugins/simulator/msfs2024/simulatormsfs2024common.h create mode 100644 src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp create mode 100644 src/swiftdata/swiftdataapplication.cpp create mode 100644 src/swiftdata/swiftdataapplication.h diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e42ed8fd4a..f17db51e50 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,9 @@ env: bitrock_version: qt-professional-24.7.0 bitrock_url: https://releases.installbuilder.com/installbuilder externals: swift-project/externals - externals_sha: dfe49bbeb8f0ca664afa293ad3f454cffe751acf + externals_sha: e1f1743ba159e11b0c065ea8f1ae1a0e91e3bf39 + + use_externals: ${{ secrets.EXTERNALS_PAT != '' }} jobs: diff --git a/.gitignore b/.gitignore index 759db19d52..04e080afc3 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,5 @@ cmake-build-*/ /dist/ CMakeUserPresets.json /third_party/externals +/src/plugins/simulator/msfs2024/simulatormsfs2024.cpp_ +/src/plugins/simulator/msfs2024/simulatormsfs2024.h_ diff --git a/src/core/db/databaseutils.cpp b/src/core/db/databaseutils.cpp index fca32ae61b..d403210874 100644 --- a/src/core/db/databaseutils.cpp +++ b/src/core/db/databaseutils.cpp @@ -75,6 +75,7 @@ namespace swift::core::db dbModelModified.updateMissingParts(model); dbModelModified.setDistributorOrder(distributorOrder); dbModelModified.setSimulator(dbModel.getSimulator()); // DB simulator settings have priority + dbModelModified.setModelLivery(model.getModelLivery()); // keep local livery settings msfs2024 return dbModelModified; } @@ -88,6 +89,7 @@ namespace swift::core::db { if (modified) { *modified = true; } consolidatedModel.setLivery(dbLivery); + consolidatedModel.setModelLivery(model.getModelLivery()); // keep local livery settings msfs2024 } } if (!consolidatedModel.getAircraftIcaoCode().hasValidDbKey() && consolidatedModel.hasAircraftDesignator()) @@ -99,6 +101,7 @@ namespace swift::core::db { if (modified) { *modified = true; } consolidatedModel.setAircraftIcaoCode(dbIcao); + consolidatedModel.setModelLivery(model.getModelLivery()); // keep local livery settings msfs2024 } } @@ -108,6 +111,7 @@ namespace swift::core::db { if (modified) { *modified = true; } consolidatedModel.setDistributor(dbDistributor); + consolidatedModel.setModelLivery(model.getModelLivery()); // keep local livery settings msfs2024 } consolidatedModel.updateLocalFileNames(model); consolidatedModel.setDistributorOrder(distributorOrder); diff --git a/src/core/modelsetbuilder.cpp b/src/core/modelsetbuilder.cpp index 56c457b0c9..93b717fbbb 100644 --- a/src/core/modelsetbuilder.cpp +++ b/src/core/modelsetbuilder.cpp @@ -49,8 +49,9 @@ namespace swift::core } else { - // without any information we can not use them - modelSet = modelSet.findWithKnownAircraftDesignator(); + if (!options.testFlag(ShowAllInstalledModells)) + // without any information we can not use them + modelSet = modelSet.findWithKnownAircraftDesignator(); } // Include only diff --git a/src/core/modelsetbuilder.h b/src/core/modelsetbuilder.h index c851377075..31dfe05180 100644 --- a/src/core/modelsetbuilder.h +++ b/src/core/modelsetbuilder.h @@ -34,7 +34,8 @@ namespace swift::core OnlyDbIcaoCodes = 1 << 2, Incremental = 1 << 3, SortByDistributors = 1 << 4, - ConsolidateWithDb = 1 << 5 + ConsolidateWithDb = 1 << 5, + ShowAllInstalledModells = 1 << 6, }; Q_DECLARE_FLAGS(Builder, BuilderFlag) diff --git a/src/gui/components/dbownmodelscomponent.cpp b/src/gui/components/dbownmodelscomponent.cpp index 6b94c12c29..3ab117f419 100644 --- a/src/gui/components/dbownmodelscomponent.cpp +++ b/src/gui/components/dbownmodelscomponent.cpp @@ -280,10 +280,10 @@ namespace swift::gui::components { QMessageBox msgBox(QMessageBox::Question, "Reload models from disk", QStringLiteral("Completely reload '%1' models from disk?").arg(simulator.toQString(true)), - QMessageBox::Ok | QMessageBox::Cancel, this); + QMessageBox::Yes | QMessageBox::No, this); msgBox.setDefaultButton(QMessageBox::Cancel); const QMessageBox::StandardButton reply = static_cast(msgBox.exec()); - if (reply != QMessageBox::Ok) { return; } + if (reply != QMessageBox::Yes) { return; } this->requestSimulatorModels(simulator, IAircraftModelLoader::InBackgroundNoCache); } @@ -335,6 +335,21 @@ namespace swift::gui::components ui->tvp_OwnAircraftModels->updateContainerMaybeAsync(this->getOwnModels()); } + // TODO TZ this is a stub for SimConnect loading + void CDbOwnModelsComponent::loadInstalledModelsSimConnect(const CSimulatorInfo &simulator, + IAircraftModelLoader::LoadMode mode, + const QStringList &modelDirectories) + { + Q_UNUSED(mode); + Q_UNUSED(modelDirectories); + + using namespace std::chrono_literals; + const CStatusMessage msg = CLogMessage(this).info(u"Start loading models for %1") << simulator.toQString(); + this->showOverlayHTMLMessage(msg, 2s); + + return; + } + void CDbOwnModelsComponent::loadInstalledModels(const CSimulatorInfo &simulator, IAircraftModelLoader::LoadMode mode, const QStringList &modelDirectories) @@ -515,7 +530,11 @@ namespace swift::gui::components IAircraftModelLoader::LoadMode mode, const QStringList &modelDirectories) { - this->loadInstalledModels(simulator, mode, modelDirectories); + // At this point, we switch how the models should be loaded: SimConnect or classic file search + if (simulator.isMSFS2024()) + this->loadInstalledModelsSimConnect(simulator, mode, modelDirectories); + else + this->loadInstalledModels(simulator, mode, modelDirectories); } void CDbOwnModelsComponent::requestSimulatorModelsWithCacheInBackground(const CSimulatorInfo &simulator) diff --git a/src/gui/components/dbownmodelscomponent.h b/src/gui/components/dbownmodelscomponent.h index b470513504..6854ac3e6b 100644 --- a/src/gui/components/dbownmodelscomponent.h +++ b/src/gui/components/dbownmodelscomponent.h @@ -153,6 +153,8 @@ namespace swift::gui void ownModelsSimulatorChanged(const swift::misc::simulation::CSimulatorInfo &simulator); private: + static constexpr std::chrono::milliseconds OverlayMsgTimeout { 5000 }; //!< how long overlay is displayed + QScopedPointer ui; swift::misc::simulation::IAircraftModelLoader *m_modelLoader = nullptr; //!< read own aircraft models, aka models on disk @@ -167,7 +169,12 @@ namespace swift::gui //! Request own models void requestOwnModelsUpdate(); - //! Load the models + //! Load the models via SimConnect + void loadInstalledModelsSimConnect(const swift::misc::simulation::CSimulatorInfo &simulator, + swift::misc::simulation::IAircraftModelLoader::LoadMode mode, + const QStringList &modelDirectories = {}); + + //! Load the models via disk void loadInstalledModels(const swift::misc::simulation::CSimulatorInfo &simulator, swift::misc::simulation::IAircraftModelLoader::LoadMode mode, const QStringList &modelDirectories = {}); diff --git a/src/gui/components/mappingcomponent.ui b/src/gui/components/mappingcomponent.ui index f06bb5f7d8..da52efbf99 100644 --- a/src/gui/components/mappingcomponent.ui +++ b/src/gui/components/mappingcomponent.ui @@ -1,358 +1,359 @@ - CMappingComponent - - - - 0 - 0 - 376 - 293 - - - - Mapping component - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - - 0 + CMappingComponent + + + + 0 + 0 + 376 + 293 + + + + Mapping component + + + + 0 - - - Rendered aircraft - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - false - - - - - - - - Aircraft models - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - false - - - - - - - - Statistics - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - Matching log - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - 16777215 - 80 - + + 0 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - validate - - - - - - - Icon - - - - - - - do all matchings again - - - re-match - - - - - - - save selected model - - - save - - - - - - - reset model by callsign - - - reset - - - - :/pastel/icons/pastel/16/arrow-refresh.png:/pastel/icons/pastel/16/arrow-refresh.png - - - - - - - callsign of aircraft - - - 15 - - - true - - - callsign - - - - - - - load model set - - - load model set - - - - - - - aircraft enabled - - - Enbl. - - - - - - - - 50 - 0 - - - - - - - - - 0 - 20 - - - - - - - - show / hide icon of aircraft - - - - - - false - - - - - - - aircraft enabled/disable - - - - + + 0 + + + 0 + + + + + Qt::Vertical + + + + 0 + + + + Rendered aircraft + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + + + + + + Aircraft models + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + + + + + + Statistics + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + Matching log + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + 16777215 + 80 + + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + validate + + + + + + + Icon + + + + + + + do all matchings again + + + re-match + + + + + + + save selected model + + + save + + + + + + + reset model by callsign + + + reset + + + + :/pastel/icons/pastel/16/arrow-refresh.png:/pastel/icons/pastel/16/arrow-refresh.png + + + + + + + + callsign of aircraft + + + 15 + + + true + + + callsign + + + + + + + load model set + + + load model set + + + + + + + aircraft enabled + + + Enbl. + + + + + + + + 50 + 0 + + + + + + + + + 0 + 20 + + + + + + + + show / hide icon of aircraft + + + + + + false + + + + + + + aircraft enabled/disable + + + + + + + + - - - - - - - - - - swift::gui::views::CAircraftModelView - QTableView -
gui/views/aircraftmodelview.h
-
- - swift::gui::components::CSimulatorSelector - QFrame -
gui/components/simulatorselector.h
- 1 -
- - swift::gui::views::CSimulatedAircraftView - QTableView -
gui/views/simulatedaircraftview.h
-
- - swift::gui::components::CModelMatcherLogComponent - QFrame -
gui/components/modelmatcherlogcomponent.h
- 1 -
- - swift::gui::components::CAircraftModelStringCompleter - QFrame -
gui/components/aircraftmodelstringcompleter.h
- 1 -
- - swift::gui::components::CMatchingStatisticsComponent - QFrame -
gui/components/matchingstatisticscomponent.h
- 1 -
-
- - tw_SpecializedViews - tvp_RenderedAircraft - cb_AircraftIconDisplayed - pb_ValidateModelSet - cb_AircraftEnabled - le_Callsign - pb_ResetAircraft - pb_DoMatchingAgain - pb_SaveAircraft - tvp_AircraftModels - - - - - + + + + + + swift::gui::views::CAircraftModelView + QTableView +
gui/views/aircraftmodelview.h
+
+ + swift::gui::components::CSimulatorSelector + QFrame +
gui/components/simulatorselector.h
+ 1 +
+ + swift::gui::views::CSimulatedAircraftView + QTableView +
gui/views/simulatedaircraftview.h
+
+ + swift::gui::components::CModelMatcherLogComponent + QFrame +
gui/components/modelmatcherlogcomponent.h
+ 1 +
+ + swift::gui::components::CAircraftModelStringCompleter + QFrame +
gui/components/aircraftmodelstringcompleter.h
+ 1 +
+ + swift::gui::components::CMatchingStatisticsComponent + QFrame +
gui/components/matchingstatisticscomponent.h
+ 1 +
+
+ + tw_SpecializedViews + tvp_RenderedAircraft + cb_AircraftIconDisplayed + pb_ValidateModelSet + cb_AircraftEnabled + le_Callsign + pb_ResetAircraft + pb_DoMatchingAgain + pb_SaveAircraft + tvp_AircraftModels + + + + +
diff --git a/src/gui/components/settingssimulatorbasicscomponent.cpp b/src/gui/components/settingssimulatorbasicscomponent.cpp index 44577e1750..25cd3d4366 100644 --- a/src/gui/components/settingssimulatorbasicscomponent.cpp +++ b/src/gui/components/settingssimulatorbasicscomponent.cpp @@ -138,12 +138,16 @@ namespace swift::gui::components s.setSimulatorDirectory(simulatorDir); s.setModelDirectories(modelDirs); s.setModelExcludeDirectories(relativeDirs); + s.setPropertyModelSet(ui->cb_LoadNewModelset->isChecked()); + s.setPropertyWithDbEntry(ui->cb_WithDbEntry->isChecked()); + s.setPropertyDistributorFiltered(ui->cb_DistributorFiltered->isChecked()); + const CStatusMessageList msgs = m_settings.setAndValidateSettings(s, simulator); if (msgs.isSuccess()) { const CStatusMessage m = m_settings.setAndSaveSettings(s, simulator); if (!m.isEmpty()) { CLogMessage::preformatted(m); } - if (m.isSuccess()) { this->showOverlayHTMLMessage("Saved settings", 5s); } + if (m.isSuccess()) { this->showOverlayHTMLMessage("Saved settings", 2s); } else { this->showOverlayMessage(m); } m_unsavedChanges = m_unsavedChanges && !m.isSuccess(); // reset if success, but only if there were changes @@ -227,6 +231,40 @@ namespace swift::gui::components { const CSimulatorInfo simulator(ui->comp_SimulatorSelector->getValue()); this->displaySettings(simulator); + + // special handling for MSFS 2024 only visual changes + if (simulator == CSimulatorInfo::msfs2024()) + { + ui->gb_ModelSet->setVisible(true); + ui->lbl_ExcludeDirectories->setText(QStringLiteral("modelstring exclude patterns:")); + ui->lbl_ModelDirectory->setText(QStringLiteral("modelstring filter patterns:")); + ui->lbl_ModelDirectory->setToolTip( + QStringLiteral("If the field is not empty, these patterns are used as a filter for the model string.")); + ui->pb_AdjustModelDirectory->setVisible(false); + ui->pb_ExcludeFileDialog->setVisible(false); + ui->pb_ModelFileDialog->setVisible(false); + const QString html = + "

"These " + "filter settings are applied to the model string passed from the flight simulator to swift. If the " + "effect is unclear, start with the default settings!".

"; + ui->lbl_ModelDirsInfo->setText(html); + } + else + { + ui->gb_ModelSet->setVisible(false); + ui->lbl_ExcludeDirectories->setText(QStringLiteral("Exclude directory patterns:")); + ui->lbl_ModelDirectory->setText(QStringLiteral("Model directories:")); + ui->lbl_ModelDirectory->setToolTip(QStringLiteral("remove redundant directories, fix file paths ..")); + ui->pb_AdjustModelDirectory->setVisible(true); + ui->pb_ExcludeFileDialog->setVisible(true); + ui->pb_ModelFileDialog->setVisible(true); + const QString html = + "

"If you change the model " + "directories, you must update your model set. See documentation. ".

"; + ui->lbl_ModelDirsInfo->setText(html); + } + this->displayDefaultValuesAsPlaceholder(simulator); } @@ -326,8 +364,27 @@ namespace swift::gui::components void CSettingsSimulatorBasicsComponent::displaySettings(const CSimulatorInfo &simulator) { - this->displayExcludeDirectoryPatterns(m_settings.getModelExcludeDirectoryPatternsIfNotDefault(simulator)); - this->displayModelDirectories(m_settings.getModelDirectoriesIfNotDefault(simulator)); + // if (simulator.isMSFS2024()) + //{ + + // //CSpecializedSimulatorSettings settings = this->getSimulatorSettings(simulator.isMSFS2024()); + // //CSimulatorSettings m_generic = settings.getGenericSettings(); + // //QStringList excludePatterns = m_generic.getModelExcludeDirectoryPatterns(); + // //QStringList filterPatterns = m_generic.getModelDirectories(); + + // //const CSimulatorSettings s = m_settings.getSettings(simulator); + // //const QString es = s.getSimulatorDirectory(); + // ui->pte_ModelDirectories->clear(); + // ui->pte_ExcludeDirectories->clear(); + + // //this->displayModelDirectories(excludePatterns); + // //this->displayExcludeDirectoryPatterns(filterPatterns); + //} + // else + //{ + // this->displayModelDirectories(m_settings.getModelDirectoriesIfNotDefault(simulator)); + // this->displayExcludeDirectoryPatterns(m_settings.getModelExcludeDirectoryPatternsIfNotDefault(simulator)); + //} // ui->le_SimulatorDirectory->setText(m_settings.getSimulatorDirectoryIfNotDefault(simulator)); // based on discussion here, always display: @@ -339,26 +396,59 @@ namespace swift::gui::components void CSettingsSimulatorBasicsComponent::displayDefaultValuesAsPlaceholder(const CSimulatorInfo &simulator) { const QString simDir = this->getFileBrowserSimulatorDirectory(); - ui->le_SimulatorDirectory->setPlaceholderText(simDir.isEmpty() ? "Simulator directory" : simDir); + + // only real placeholder shut set as placeholder + simDir.isEmpty() ? (ui->le_SimulatorDirectory->setPlaceholderText("Simulator directory")) : + (ui->le_SimulatorDirectory->setText(simDir)); // we take the settings and update to latest sim.directory CSpecializedSimulatorSettings settings = m_settings.getSpecializedSettings(simulator); settings.setSimulatorDirectory(simDir); - const QStringList m = settings.getModelDirectoriesFromSimulatorDirectoryOrDefault(); - if (m.isEmpty()) { ui->pte_ModelDirectories->setPlaceholderText("Model directories"); } - else + CSimulatorSettings m_generic = settings.getGenericSettings(); + + // this setting is only visable for msfs2024 but we set it always to keep code simple. the checkbox is hidden in + // other simulators this settings are used to load/not load the modelset when starting swiftgui + ui->cb_WithDbEntry->setChecked(m_generic.getPropertyWithDbEntry()); + ui->cb_DistributorFiltered->setChecked(m_generic.getPropertyDistributorFiltered()); + ui->cb_LoadNewModelset->setChecked(m_generic.getPropertyModelSet()); + + // Storeable content should be displayed as planetext so that it is actually saved. + if (simulator.isMSFS2024()) { - const QString ms = m.join("\n"); - ui->pte_ModelDirectories->setPlaceholderText(ms); + QStringList m = m_generic.getModelDirectories(); + if (m.isEmpty()) { ui->pte_ModelDirectories->setPlainText("*"); } + else + { + const QString ms = m.join("\n"); + ui->pte_ModelDirectories->setPlainText(ms); + } + + QStringList e = m_generic.getModelExcludeDirectoryPatterns(); + if (e.isEmpty()) { ui->pte_ExcludeDirectories->setPlainText("PassiveAircraft\nSTUB\nZZZZ"); } + else + { + const QString es = e.join("\n"); + ui->pte_ExcludeDirectories->setPlainText(es); + } } - - const QStringList e = settings.getDefaultModelExcludeDirectoryPatterns(); - if (e.isEmpty()) { ui->pte_ExcludeDirectories->setPlaceholderText("Exclude directories"); } else { - const QString es = e.join("\n"); - ui->pte_ExcludeDirectories->setPlaceholderText(es); + const QStringList m = settings.getModelDirectoriesFromSimulatorDirectoryOrDefault(); + if (m.isEmpty()) { ui->pte_ModelDirectories->setPlaceholderText("Model directories"); } + else + { + const QString ms = m.join("\n"); + ui->pte_ModelDirectories->setPlainText(ms); + } + + const QStringList e = settings.getDefaultModelExcludePatterns(); + if (e.isEmpty()) { ui->pte_ExcludeDirectories->setPlaceholderText("Exclude directories"); } + else + { + const QString es = e.join("\n"); + ui->pte_ExcludeDirectories->setPlainText(es); + } } } diff --git a/src/gui/components/settingssimulatorbasicscomponent.ui b/src/gui/components/settingssimulatorbasicscomponent.ui index a34d86d8b3..08f847500a 100644 --- a/src/gui/components/settingssimulatorbasicscomponent.ui +++ b/src/gui/components/settingssimulatorbasicscomponent.ui @@ -1,195 +1,268 @@ - CSettingsSimulatorBasicsComponent - - - - 0 - 0 - 459 - 347 - - - - Simulator basic settings - - - - 3 - - - 3 - - - 3 - - - 3 - - - - - Model directories - - - - - - - Simulator: - - - - - - - remove redundant directories, fix file paths ... - - - adjust - - - - - - - Excluded from model loading - - - Exclude directory patterns: - - - - - - - - 150 - 25 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Minimum - - - - 50 - 20 - - - - - - - - save - - - - - - - reset - - - - - - - Simulator directory: - - - - - - - Model directories: - - - - - - - ... - - - - - - - ... - - - - - - - Excluded directory patterns - - - QPlainTextEdit::NoWrap - - - Excluded directory patterns - - - - - - - Simulator directory path - - - - - - - copy (materialize) defaults - - - copy def. - - - - - - - ... - - - - - - - <html><head/><body><p><img src=":/diagona/icons/diagona/icons/exclamation--frame.png"/> Changing model directories means you have to update your model set! Check documentation on &quot;creating a model set&quot;.</p></body></html> - - - true - - - - - - - - swift::gui::components::CSimulatorSelector - QFrame -
gui/components/simulatorselector.h
- 1 -
-
- - le_SimulatorDirectory - pte_ModelDirectories - pte_ExcludeDirectories - - - + CSettingsSimulatorBasicsComponent + + + + 0 + 0 + 459 + 347 + + + + Simulator basic settings + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Model directories + + + + + + + Simulator: + + + + + + + + remove redundant directories, fix file paths ... + + + adjust + + + + + + + Excluded from model loading + + + Exclude directory patterns: + + + + + + + + 0 + 100 + + + + Model set handling + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + true + + + Create new modelset when swiftgui starts? + + + Every time swiftgui is restarted, the models currently in the simulator are read in and a new model set is created + + + + + + + Load models only with database entries + + + Only models with swift database entry are used + + + + + + + Distributors filtered? + + + Only the distributors from the configuration file are used + + + + + + + + + + + 150 + 25 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 50 + 20 + + + + + + + + save + + + + + + + reset + + + Sets the input mask to the default values ​​and deletes the saved values. + + + + + + + Simulator directory: + + + + + + + Model directories: + + + remove redundant directories, fix file paths ... + + + + + + + ... + + + + + + + ... + + + + + + + Excluded directory patterns + + + QPlainTextEdit::NoWrap + + + Excluded directory patterns + + + + + + + Simulator directory path + + + + + + + copy (materialize) defaults + + + copy def. + + + + + + + ... + + + + + + + <html><head/><body><p><img src=":/diagona/icons/diagona/icons/exclamation--frame.png"/> Changing model directories means you have to update your model set! Check documentation on &quot;creating a model set&quot;.</p></body></html> + + + true + + + + 150 + 100 + + + + + + + + + swift::gui::components::CSimulatorSelector + QFrame +
gui/components/simulatorselector.h
+ 1 +
+
+ + le_SimulatorDirectory + pte_ModelDirectories + pte_ExcludeDirectories + + +
diff --git a/src/gui/editors/ownmodelsetform.ui b/src/gui/editors/ownmodelsetform.ui index c075c493da..99ecf31ca8 100644 --- a/src/gui/editors/ownmodelsetform.ui +++ b/src/gui/editors/ownmodelsetform.ui @@ -164,6 +164,9 @@ all shown below + + true + bg_Distributors @@ -194,9 +197,6 @@ all distributors - - true - bg_Distributors diff --git a/src/gui/models/aircraftmodellistmodel.cpp b/src/gui/models/aircraftmodellistmodel.cpp index 9d6f69bab6..5645007034 100644 --- a/src/gui/models/aircraftmodellistmodel.cpp +++ b/src/gui/models/aircraftmodellistmodel.cpp @@ -36,6 +36,7 @@ namespace swift::gui::models (void)QT_TRANSLATE_NOOP("CAircraftModelListModel", "model"); } + // TODO TZ check if some columns can be hidden automatically for different sims void CAircraftModelListModel::setAircraftModelMode(CAircraftModelListModel::AircraftModelMode mode) { if (m_mode == mode) { return; } @@ -45,7 +46,10 @@ namespace swift::gui::models { case NotSet: case OwnAircraftModelClient: - m_columns.addColumn(CColumn::standardString("model", { CAircraftModel::IndexModelString })); + // m_columns.addColumn(CColumn::standardString("model", { CAircraftModel::IndexModelString })); + m_columns.addColumn(CColumn::standardString("model", { CAircraftModel::IndexShortModelString })); + + m_columns.addColumn(CColumn::standardString("liverypart", CAircraftModel::IndexModelLivery)); m_columns.addColumn( CColumn("DB", "DB metadata", CAircraftModel::IndexDatabaseIcon, new CPixmapFormatter())); m_columns.addColumn( @@ -82,7 +86,9 @@ namespace swift::gui::models case OwnAircraftModelMappingTool: case StashModel: - m_columns.addColumn(CColumn::standardString("model", CAircraftModel::IndexModelString)); + m_columns.addColumn(CColumn::standardString("model", CAircraftModel::IndexShortModelString)); + + m_columns.addColumn(CColumn::standardString("liverypart", CAircraftModel::IndexModelLivery)); m_columns.addColumn( CColumn("DB", "DB metadata", CAircraftModel::IndexDatabaseIcon, new CPixmapFormatter())); if (mode == StashModel) diff --git a/src/misc/CMakeLists.txt b/src/misc/CMakeLists.txt index 40bd0d4c2f..74c38efe94 100644 --- a/src/misc/CMakeLists.txt +++ b/src/misc/CMakeLists.txt @@ -533,6 +533,8 @@ add_library(misc SHARED simulation/flightgear/aircraftmodelloaderflightgear.h simulation/flightgear/flightgearutil.cpp simulation/flightgear/flightgearutil.h + simulation/msfs2024/aircraftmodelloadermsfs2024.cpp + simulation/msfs2024/aircraftmodelloadermsfs2024.h simulation/fscommon/aircraftcfgentries.cpp simulation/fscommon/aircraftcfgentries.h simulation/fscommon/aircraftcfgentrieslist.cpp diff --git a/src/misc/simulation/aircraftmodel.cpp b/src/misc/simulation/aircraftmodel.cpp index f63aa00c03..cc69cf7739 100644 --- a/src/misc/simulation/aircraftmodel.cpp +++ b/src/misc/simulation/aircraftmodel.cpp @@ -42,6 +42,10 @@ namespace swift::misc::simulation : m_modelString(model.trimmed().toUpper()), m_modelType(type) {} + CAircraftModel::CAircraftModel(const QString &model, const QString &livery, CAircraftModel::ModelType type) + : m_modelString(model.trimmed().toUpper()), m_modelLivery(livery.trimmed().toUpper()), m_modelType(type) + {} + CAircraftModel::CAircraftModel(const QString &model, CAircraftModel::ModelType type, const CAircraftIcaoCode &icao, const CLivery &livery) : m_aircraftIcao(icao), m_livery(livery), m_modelString(model.trimmed().toUpper()), m_modelType(type) @@ -237,6 +241,12 @@ namespace swift::misc::simulation return this->getAllModelStringsAndAliases() % " " % this->getDbKeyAsStringInParentheses(); } + QString CAircraftModel::getMsfs2024Modelstring() + { + m_modelString = m_modelString.trimmed().toUpper() % u" " % m_modelLivery.trimmed().toUpper(); + return m_modelString; + } + bool CAircraftModel::isVtol() const { return this->getAircraftIcaoCode().isVtol(); } QVariant CAircraftModel::propertyByIndex(swift::misc::CPropertyIndexRef index) const @@ -274,6 +284,8 @@ namespace swift::misc::simulation case IndexLivery: return m_livery.propertyByIndex(index.copyFrontRemoved()); case IndexCallsign: return m_callsign.propertyByIndex(index.copyFrontRemoved()); case IndexMembersDbStatus: return this->getMembersDbStatus(); + case IndexModelLivery: return QVariant(m_modelLivery); + case IndexShortModelString: return QVariant(getShortModelString()); default: return CValueObject::propertyByIndex(index); } } @@ -584,6 +596,23 @@ namespace swift::misc::simulation return (sim.isFG()) ? this->getSwiftLiveryString(true, false, false) : this->getSwiftLiveryString(); } + QString CAircraftModel::getShortModelString() const + { + + QString shortModelString = m_modelString; + if (m_modelString.contains(m_modelLivery)) + { + int lastIndex = m_modelString.lastIndexOf(m_modelLivery); + + if (lastIndex != -1) + { + const QString newModelString = m_modelString.left(lastIndex); + shortModelString = newModelString; + } + } + return shortModelString; + } + DBTripleIds CAircraftModel::parseNetworkLiveryString(const QString &liveryString) { // "swift_m22l33a11" @@ -766,6 +795,13 @@ namespace swift::misc::simulation return (p.contains(path, cs)); } + bool CAircraftModel::matchesModelStringAndLivery(const QString &modelString, const QString &modelLivery, + Qt::CaseSensitivity sensitivity) const + { + return (stringCompare(modelString, m_modelString, sensitivity) && + stringCompare(modelLivery, m_modelLivery, sensitivity)); + } + bool CAircraftModel::matchesModelString(const QString &modelString, Qt::CaseSensitivity sensitivity) const { return stringCompare(modelString, m_modelString, sensitivity); @@ -999,6 +1035,7 @@ namespace swift::misc::simulation const QString modelName(json.value(prefix % u"name").toString()); const QString modelMode(json.value(prefix % u"mode").toString()); const QString parts(json.value(prefix % u"parts").toString()); + const QString modelLivery(json.value(prefix % u"modellivery").toString()); // check for undefined to rule out 0ft values const QJsonValue cgjv = json.value(prefix % u"cgft"); @@ -1008,6 +1045,7 @@ namespace swift::misc::simulation const CSimulatorInfo simInfo = CSimulatorInfo::fromDatabaseJson(json, prefix); CAircraftModel model(modelString, CAircraftModel::TypeDatabaseEntry, simInfo, modelName, modelDescription); model.setModelStringAlias(modelStringAlias); + model.setModelLivery(modelLivery); // msfs2024 model.setModelModeAsString(modelMode); model.setSupportedParts(parts); model.setCG(cg); diff --git a/src/misc/simulation/aircraftmodel.h b/src/misc/simulation/aircraftmodel.h index 2cc21462cf..04066c8866 100644 --- a/src/misc/simulation/aircraftmodel.h +++ b/src/misc/simulation/aircraftmodel.h @@ -83,7 +83,9 @@ namespace swift::misc TypeManuallySet, //!< manually set, e.g. from GUI TypeOwnSimulatorModel, //!< represents own simulator model (AI model, model on disk) TypeVPilotRuleBased, //!< based on a vPilot rule - TypeTerrainProbe //!< peudo aircraft used for terrain probing (FSX) + TypeTerrainProbe, //!< peudo aircraft used for terrain probing (FSX) + TypeOwnSimulatorLivery //!< represents own simulator model livery (msfs2024) + }; //! Mode, decides if a model is supposed to be used in the model set for model matching @@ -124,7 +126,9 @@ namespace swift::misc IndexSupportedParts, IndexModelModeAsIcon, IndexHasQueriedModelString, - IndexMembersDbStatus + IndexMembersDbStatus, + IndexModelLivery, // MSFS2024 + IndexShortModelString, }; //! \copydoc swift::misc::CValueObject::registerMetadata @@ -136,6 +140,9 @@ namespace swift::misc //! Constructor. CAircraftModel(const QString &model, ModelType type); + //! Constructor. + CAircraftModel(const QString &model, const QString &livery, ModelType type); + //! Constructor. CAircraftModel(const QString &model, ModelType type, const aviation::CAircraftIcaoCode &icao, const aviation::CLivery &livery); @@ -181,12 +188,21 @@ namespace swift::misc //! Model key, either queried or loaded from simulator model const QString &getModelString() const { return m_modelString; } + //! Model Livery, part of model string in MSFS 2024 + const QString &getModelLivery() const { return m_modelLivery; } + //! Model string and DB key (if available) QString getModelStringAndDbKey() const; //! Model string void setModelString(const QString &modelString) { m_modelString = modelString.trimmed().toUpper(); } + //! Model livery msfs2024 + void setModelLivery(const QString &modelLivery) { m_modelLivery = modelLivery.trimmed().toUpper(); } + + //! Model livery whitout part for lifery msfs2024 + QString getShortModelString() const; + //! Model key, either queried or loaded from simulator model const QString &getModelStringAlias() const { return m_modelStringAlias; } @@ -196,6 +212,9 @@ namespace swift::misc //! Get model string and aliases QString getAllModelStringsAliasesAndDbKey() const; + //! Get model string and Livery + QString getMsfs2024Modelstring(); + //! Model string alias void setModelStringAlias(const QString &alias) { m_modelStringAlias = alias.trimmed().toUpper(); } @@ -419,6 +438,10 @@ namespace swift::misc //! Matches model string? bool matchesModelString(const QString &modelString, Qt::CaseSensitivity sensitivity) const; + //! Matches model string and livery? + bool matchesModelStringAndLivery(const QString &modelString, const QString &modelLivery, + Qt::CaseSensitivity sensitivity) const; + //! Matches model string or alias? bool matchesModelStringOrAlias(const QString &modelString, Qt::CaseSensitivity sensitivity) const; @@ -567,11 +590,13 @@ namespace swift::misc CSimulatorInfo m_simulator; //!< model for given simulator CDistributor m_distributor; //!< who designed or distributed the model QString m_modelString; //!< Simulator model key, unique + QString m_modelLivery; //!< Simulator livery (msfs2024) QString m_modelStringAlias; //!< Simulator model key alias, unique QString m_name; //!< Model name QString m_description; //!< descriptive text QString m_fileName; //!< file name QString m_supportedParts; //!< supported parts + QString m_shortModelString; //!< cached short model string qint64 m_fileTimestamp = -1; //!< file timestamp of originating file (if applicable) ModelType m_modelType = TypeUnknown; //!< model string is coming representing ...? ModelMode m_modelMode = Include; //!< model mode (include / exclude) @@ -591,6 +616,7 @@ namespace swift::misc SWIFT_METAMEMBER(supportedParts), SWIFT_METAMEMBER(modelString, 0, CaseInsensitiveComparison), SWIFT_METAMEMBER(modelStringAlias, 0, CaseInsensitiveComparison), + SWIFT_METAMEMBER(modelLivery, 0, CaseInsensitiveComparison), SWIFT_METAMEMBER(name), SWIFT_METAMEMBER(description, 0, DisabledForComparison), SWIFT_METAMEMBER(fileName, 0, DisabledForComparison), diff --git a/src/misc/simulation/aircraftmodellist.cpp b/src/misc/simulation/aircraftmodellist.cpp index 309e865269..c994a2803e 100644 --- a/src/misc/simulation/aircraftmodellist.cpp +++ b/src/misc/simulation/aircraftmodellist.cpp @@ -731,12 +731,14 @@ namespace swift::misc::simulation return d; } - bool CAircraftModelList::removeModelWithString(const QString &modelString, Qt::CaseSensitivity sensitivity) + bool CAircraftModelList::removeModelWithString(const QString &modelString, const QString &modelLivery, + Qt::CaseSensitivity sensitivity) { if (modelString.isEmpty()) { return false; } if (this->isEmpty()) { return false; } - const int r = this->removeIf( - [&](const CAircraftModel &model) { return model.matchesModelString(modelString, sensitivity); }); + const int r = this->removeIf([&](const CAircraftModel &model) { + return model.matchesModelStringAndLivery(modelString, modelLivery, sensitivity); + }); return r > 0; } @@ -849,7 +851,11 @@ namespace swift::misc::simulation Qt::CaseSensitivity sensitivity) { bool r = false; - if (!this->isEmpty()) { r = this->removeModelWithString(addOrReplaceModel.getModelString(), sensitivity); } + if (!this->isEmpty()) + { + r = this->removeModelWithString(addOrReplaceModel.getModelString(), addOrReplaceModel.getModelLivery(), + sensitivity); + } this->push_back(addOrReplaceModel); return r; } @@ -907,6 +913,18 @@ namespace swift::misc::simulation return ms; } + QStringList CAircraftModelList::getModelStringAndLiveryList(bool sort) const + { + QStringList ms; + for (const CAircraftModel &model : *this) + { + if (!model.hasModelString()) { continue; } + ms.append(model.getModelString() + "{" + model.getModelLivery() + "}"); + } + if (sort) { ms.sort(Qt::CaseInsensitive); } + return ms; + } + QSet CAircraftModelList::getModelStringSet() const { CSetBuilder ms; @@ -1731,12 +1749,12 @@ namespace swift::misc::simulation if (valid) { validModels.push_back(model); - invalidModels.removeModelWithString(model.getModelString(), Qt::CaseInsensitive); + invalidModels.removeModelWithString(model.getModelString(), model.getModelLivery(), Qt::CaseInsensitive); } else { invalidModels.push_back(model); - validModels.removeModelWithString(model.getModelString(), Qt::CaseInsensitive); + validModels.removeModelWithString(model.getModelString(), model.getModelLivery(), Qt::CaseInsensitive); } } diff --git a/src/misc/simulation/aircraftmodellist.h b/src/misc/simulation/aircraftmodellist.h index 2fd3c21278..0c595543a3 100644 --- a/src/misc/simulation/aircraftmodellist.h +++ b/src/misc/simulation/aircraftmodellist.h @@ -334,7 +334,8 @@ namespace swift::misc //! Remove those models with given model strings //! \return number of elements removed - bool removeModelWithString(const QString &modelString, Qt::CaseSensitivity sensitivity); + bool removeModelWithString(const QString &modelString, const QString &modelLivery, + Qt::CaseSensitivity sensitivity); //! Remove those models with given model strings //! \return number of elements removed @@ -393,6 +394,9 @@ namespace swift::misc //! Model strings QStringList getModelStringList(bool sort = true) const; + //! Model strings and Livery codes + QStringList getModelStringAndLiveryList(bool sort = true) const; + //! Model strings as set QSet getModelStringSet() const; diff --git a/src/misc/simulation/aircraftmodelloader.cpp b/src/misc/simulation/aircraftmodelloader.cpp index ce08841fe7..a5a11fb8be 100644 --- a/src/misc/simulation/aircraftmodelloader.cpp +++ b/src/misc/simulation/aircraftmodelloader.cpp @@ -131,18 +131,28 @@ namespace swift::misc::simulation return; } - // really load from disk? - const QStringList modelDirs = this->getInitializedModelDirectories(modelDirectories, simulator); - if (m_skipLoadingEmptyModelDir && modelDirs.isEmpty()) + QStringList modelDirs = { "", "" }; + if (simulator.isMSFS2024()) { - const CStatusMessage status = CStatusMessage(this, CStatusMessage::SeverityWarning, - u"Empty or not existing '%1' directory '%2', skipping read") - << simulator.toQString() << modelDirectories.join(", "); - m_loadingMessages.push_back(status); - m_loadingMessages.freezeOrder(); emit this->loadingFinished(m_loadingMessages, simulator, LoadingSkipped); return; } + else + { + // really load from disk? + modelDirs = this->getInitializedModelDirectories(modelDirectories, simulator); + if (m_skipLoadingEmptyModelDir && modelDirs.isEmpty()) + { + const CStatusMessage status = + CStatusMessage(this, CStatusMessage::SeverityWarning, + u"Empty or not existing '%1' directory '%2', skipping read") + << simulator.toQString() << modelDirectories.join(", "); + m_loadingMessages.push_back(status); + m_loadingMessages.freezeOrder(); + emit this->loadingFinished(m_loadingMessages, simulator, LoadingSkipped); + return; + } + } this->setObjectInfo(simulator); this->startLoadingFromDisk(mode, modelConsolidation, modelDirs); diff --git a/src/misc/simulation/aircraftmodelloaderprovider.cpp b/src/misc/simulation/aircraftmodelloaderprovider.cpp index f81c7e196c..ebf5c169eb 100644 --- a/src/misc/simulation/aircraftmodelloaderprovider.cpp +++ b/src/misc/simulation/aircraftmodelloaderprovider.cpp @@ -13,6 +13,7 @@ #include "misc/mixin/mixincompare.h" #include "misc/simulation/flightgear/aircraftmodelloaderflightgear.h" #include "misc/simulation/fscommon/aircraftcfgparser.h" +#include "misc/simulation/msfs2024/aircraftmodelloadermsfs2024.h" #include "misc/simulation/xplane/aircraftmodelloaderxplane.h" #include "misc/simulation/xplane/xplaneutil.h" @@ -22,6 +23,7 @@ using namespace swift::misc::simulation::settings; using namespace swift::misc::simulation::fscommon; using namespace swift::misc::simulation::flightgear; using namespace swift::misc::simulation::xplane; +using namespace swift::misc::simulation::msfs2024; namespace swift::misc::simulation { @@ -31,6 +33,7 @@ namespace swift::misc::simulation Q_ASSERT_X(simulator.isSingleSimulator(), Q_FUNC_INFO, "Single simulator"); if (simulator.isXPlane()) { return new CAircraftModelLoaderXPlane(parent); } if (simulator.isFG()) { return new CAircraftModelLoaderFlightgear(parent); } + if (simulator.isMSFS2024()) { return new CAircraftModelLoaderMsfs2024(parent); } return CAircraftCfgParser::createModelLoader(simulator, parent); } diff --git a/src/misc/simulation/aircraftmodelutils.cpp b/src/misc/simulation/aircraftmodelutils.cpp index 7682dc04e4..be8a908b03 100644 --- a/src/misc/simulation/aircraftmodelutils.cpp +++ b/src/misc/simulation/aircraftmodelutils.cpp @@ -167,9 +167,13 @@ namespace swift::misc::simulation QStringLiteral("Some of the excluded models are: '%1'").arg(ms), true)); } - // specific checks for FSX/XPlane/FG + // specific checks for FSX/XPlane/FG/MSFS CStatusMessageList specificTests; - if (simulator.isMicrosoftOrPrepare3DSimulator() || models.isLikelyFsFamilyModelList()) + if (simulator.isMSFS2024()) + { + // Placeholder, nothing to do + } + else if (simulator.isMicrosoftOrPrepare3DSimulator() || models.isLikelyFsFamilyModelList()) { const CStatusMessageList specificTests1 = fscommon::CFsCommonUtil::validateAircraftConfigFiles( models, validModels, invalidModels, ignoreEmpty, stopAtFailedFiles, wasStopped); @@ -193,12 +197,6 @@ namespace swift::misc::simulation models, validModels, invalidModels, ignoreEmpty, stopAtFailedFiles, wasStopped, simulatorDir); specificTests.push_back(specificTests2); } - else if (simulator.isMSFS2024()) - { - const CStatusMessageList specificTests2 = fscommon::CFsCommonUtil::validateMSFS2024SimObjectsPath( - models, validModels, invalidModels, ignoreEmpty, stopAtFailedFiles, wasStopped, simulatorDir); - specificTests.push_back(specificTests2); - } } else if (simulator.isXPlane() || models.isLikelyXPlaneModelList()) { diff --git a/src/misc/simulation/fscommon/aircraftcfgparser.cpp b/src/misc/simulation/fscommon/aircraftcfgparser.cpp index f9bf5448c2..8b7a52b465 100644 --- a/src/misc/simulation/fscommon/aircraftcfgparser.cpp +++ b/src/misc/simulation/fscommon/aircraftcfgparser.cpp @@ -153,11 +153,9 @@ namespace swift::misc::simulation::fscommon // set directory with name filters, get aircraft.cfg and sub directories static const QString NoNameFilter; QDir dir(directory, NoNameFilter, QDir::Name, QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot); - // TODO TZ: still have to figure out how msfs2024 handles this + // for MSFS2020 we only need aircraft.cfg - // MSFS2024 has aircraft.cfg only in communityfolder - // a solution for the aircraft from the marketplace may be prepared by ASOBO - dir.setNameFilters(fileNameFilters(getSimulator().isMSFS(), getSimulator().isMSFS2024())); + dir.setNameFilters(fileNameFilters(getSimulator().isMSFS())); if (!dir.exists()) { return CAircraftCfgEntriesList(); // can happen if there are shortcuts or linked dirs not available @@ -467,10 +465,9 @@ namespace swift::misc::simulation::fscommon return content; } - // TODO TZ: MSFS2024 currently has aircraft.cfg only in the community folder - const QStringList &CAircraftCfgParser::fileNameFilters(bool isMSFS, bool isMSFS2024) + const QStringList &CAircraftCfgParser::fileNameFilters(bool isMSFS) { - if (CBuildConfig::buildWordSize() == 32 || isMSFS || isMSFS2024) + if (CBuildConfig::buildWordSize() == 32 || isMSFS) { static const QStringList f({ "aircraft.cfg" }); return f; diff --git a/src/misc/simulation/fscommon/aircraftcfgparser.h b/src/misc/simulation/fscommon/aircraftcfgparser.h index 4fdc9bff5b..1af923bd4d 100644 --- a/src/misc/simulation/fscommon/aircraftcfgparser.h +++ b/src/misc/simulation/fscommon/aircraftcfgparser.h @@ -89,7 +89,7 @@ namespace swift::misc static QString getFixedIniLineContent(const QString &line); //! Files to be used - static const QStringList &fileNameFilters(bool isMSFS, bool isMSFS2024); + static const QStringList &fileNameFilters(bool isMSFS); //! Exclude the sub directories not to be parsed static bool isExcludedSubDirectory(const QString &excludeDirectory); diff --git a/src/misc/simulation/fscommon/fscommonutil.cpp b/src/misc/simulation/fscommon/fscommonutil.cpp index e8c8d1e0db..bd14ae5eb6 100644 --- a/src/misc/simulation/fscommon/fscommonutil.cpp +++ b/src/misc/simulation/fscommon/fscommonutil.cpp @@ -230,17 +230,6 @@ namespace swift::misc::simulation::fscommon stopAtFailedFiles, stopped); } - CStatusMessageList CFsCommonUtil::validateMSFS2024SimObjectsPath( - const CAircraftModelList &models, CAircraftModelList &validModels, CAircraftModelList &invalidModels, - bool ignoreEmptyFileNames, int stopAtFailedFiles, std::atomic_bool &stopped, const QString &simulatorDir) - { - Q_UNUSED(simulatorDir) - const QStringList simObjectPaths = CFsDirectories::msfs2024SimObjectsDirPath(); - return CFsCommonUtil::validateSimObjectsPath(QSet(simObjectPaths.begin(), simObjectPaths.end()), - models, validModels, invalidModels, ignoreEmptyFileNames, - stopAtFailedFiles, stopped); - } - CStatusMessageList CFsCommonUtil::validateSimObjectsPath(const QSet &simObjectDirs, const CAircraftModelList &models, CAircraftModelList &validModels, CAircraftModelList &invalidModels, diff --git a/src/misc/simulation/fscommon/fscommonutil.h b/src/misc/simulation/fscommon/fscommonutil.h index 07bfa55fc2..7cde5deb1d 100644 --- a/src/misc/simulation/fscommon/fscommonutil.h +++ b/src/misc/simulation/fscommon/fscommonutil.h @@ -67,15 +67,6 @@ namespace swift::misc::simulation::fscommon bool ignoreEmptyFileNames, int stopAtFailedFiles, std::atomic_bool &wasStopped, const QString &simulatorDir); - //! Validate if known SimObjects path are used - //! \remark only for MSFS2024 - static CStatusMessageList validateMSFS2024SimObjectsPath(const CAircraftModelList &models, - CAircraftModelList &validModels, - CAircraftModelList &invalidModels, - bool ignoreEmptyFileNames, int stopAtFailedFiles, - std::atomic_bool &wasStopped, - const QString &simulatorDir); - private: //! Validate if known SimObjects path are used //! \remark only for P3D/FSX diff --git a/src/misc/simulation/fscommon/fsdirectories.cpp b/src/misc/simulation/fscommon/fsdirectories.cpp index 020e32d7d3..c2e883d23b 100644 --- a/src/misc/simulation/fscommon/fsdirectories.cpp +++ b/src/misc/simulation/fscommon/fsdirectories.cpp @@ -331,6 +331,8 @@ namespace swift::misc::simulation::fscommon "OneStore/microsoft-discovery", "landingchallenge", "tutorials", + "point-of-interest", + "airport", }; return exclude; @@ -338,9 +340,7 @@ namespace swift::misc::simulation::fscommon const QStringList &CFsDirectories::msfs2024SimObjectsExcludeDirectoryPatterns() { - static const QStringList exclude { - "landingchallenge", - "tutorials", + static const QStringList exclude { "PassiveAircraft", "STUB", "ZZZZ" }; return exclude; diff --git a/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp b/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp new file mode 100644 index 0000000000..07ee7fc602 --- /dev/null +++ b/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp @@ -0,0 +1,107 @@ +// SPDX-FileCopyrightText: Copyright (C) 2019 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +// #include + +#include "misc/simulation/msfs2024/aircraftmodelloadermsfs2024.h" + +#include + +#include "misc/simulation/aircraftmodel.h" +#include "misc/simulation/settings/simulatorsettings.h" + +using namespace swift::config; +using namespace swift::misc; +using namespace swift::misc::aviation; +using namespace swift::misc::physical_quantities; +using namespace swift::misc::geo; +using namespace swift::misc::network; +using namespace swift::misc::simulation; +using namespace swift::misc::simulation::settings; +// using namespace swift::misc::math; +using namespace swift::misc::simulation::data; +// using namespace swift::misc::simulation::msfs2024; +// using namespace swift::misc::simulation::settings; + +namespace swift::misc::simulation::msfs2024 +{ + + bool CAircraftModelLoaderMsfs2024::isLoadingFinished() const + { + return !m_parserWorker || m_parserWorker->isFinished(); + ; + } + + CAircraftModelLoaderMsfs2024::CAircraftModelLoaderMsfs2024(QObject *parent) + : simulation::IAircraftModelLoader(simulation::CSimulatorInfo::msfs2024(), parent) + {} + + CAircraftModelLoaderMsfs2024::~CAircraftModelLoaderMsfs2024() + { + // that should be safe as long as the worker uses deleteLater (which it does) + if (m_parserWorker) { m_parserWorker->waitForFinished(); } + } + + void CAircraftModelLoaderMsfs2024::updateInstalledModels(const CAircraftModelList &models) + { + this->setModelsForSimulator(models, CSimulatorInfo::msfs2024()); + + const CStatusMessage m = + CStatusMessage(this, CStatusMessage::SeverityInfo, u"MSFS2024 found and updated '%1' models") + << models.size(); + m_loadingMessages.push_back(m); + } + + CAircraftModelList CAircraftModelLoaderMsfs2024::performParsing() + { + CAircraftModelList allModels; + + // TODO TZ Implement model queries via SimConnect if possible + // misc shut not include simconnect headers or plugins directly + + const CSimulatorInfo simulatorInfo = CSimulatorInfo::msfs2024(); + allModels = + CCentralMultiSimulatorModelCachesProvider::modelCachesInstance().getSynchronizedCachedModels(simulatorInfo); + + return allModels; + } + + // for msfs2024, the model information is read from the SimConnect interface and no longer from the directories via + // the aircraft.cfg + void CAircraftModelLoaderMsfs2024::startLoadingFromDisk( + IAircraftModelLoader::LoadMode mode, const IAircraftModelLoader::ModelConsolidationCallback &modelConsolidation, + const QStringList &modelDirectories) + { + + const CSimulatorInfo simulator = CSimulatorInfo::msfs2024(); + const QStringList modelDirs = this->getInitializedModelDirectories(modelDirectories, simulator); + const QStringList excludedDirectoryPatterns( + m_settings.getModelExcludeDirectoryPatternsOrDefault(simulator)); // copy + + if (mode.testFlag(LoadInBackground)) + { + if (m_parserWorker && !m_parserWorker->isFinished()) { return; } + emit this->diskLoadingStarted(simulator, mode); + + // TODO TZ simplify, we don't need directories + m_parserWorker = CWorker::fromTask(this, "CAircraftModelLoaderMsfs2024::performParsing", + [this, modelDirs, excludedDirectoryPatterns, modelConsolidation]() { + auto models = this->performParsing(); + if (modelConsolidation) { modelConsolidation(models, true); } + return models; + }); + m_parserWorker->thenWithResult(this, [=](const auto &models) { + this->updateInstalledModels(models); + m_loadingMessages.freezeOrder(); + emit this->loadingFinished(m_loadingMessages, simulator, ParsedData); + }); + } + else if (mode.testFlag(LoadDirectly)) + { + emit this->diskLoadingStarted(simulator, mode); + CAircraftModelList models(this->performParsing()); + this->updateInstalledModels(models); + } + } + +} // namespace swift::misc::simulation::msfs2024 diff --git a/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.h b/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.h new file mode 100644 index 0000000000..a7dd37cc0e --- /dev/null +++ b/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.h @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright (C) 2019 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +#ifndef SWIFT_MISC_SIMULATION_MSFS2024_AIRCRAFTMODELLOADERMSFS2024_H +#define SWIFT_MISC_SIMULATION_MSFS2024_AIRCRAFTMODELLOADERMSFS2024_H + +#include + +#include "misc/simulation/aircraftmodelloader.h" + +namespace swift::misc::simulation::msfs2024 +{ + //! Msfs2024 aircraft model loader + class CAircraftModelLoaderMsfs2024 : public IAircraftModelLoader + { + Q_OBJECT + + public: + //! Constructor + CAircraftModelLoaderMsfs2024(QObject *parent = nullptr); + + //! Virtual destructor + ~CAircraftModelLoaderMsfs2024() override; + + //! Parsed or injected models + void updateInstalledModels(const CAircraftModelList &models); + + //! \copydoc IAircraftModelLoader::isLoadingFinished + bool isLoadingFinished() const override; + + protected: + //! \copydoc IAircraftModelLoader::startLoadingFromDisk + void startLoadingFromDisk(LoadMode mode, const ModelConsolidationCallback &modelConsolidation, + const QStringList &modelDirectories) override; + + private: + QPointer m_parserWorker; + // CAircraftModelList performParsing(const QStringList &rootDirectories, const QStringList &excludeDirectories); + CAircraftModelList performParsing(); + }; + +} // namespace swift::misc::simulation::msfs2024 + +#endif // SWIFT_MISC_SIMULATION_MSFS2024_AIRCRAFTMODELLOADERMSFS2024_H diff --git a/src/misc/simulation/settings/simulatorsettings.cpp b/src/misc/simulation/settings/simulatorsettings.cpp index 896d80d5a9..cc5581676e 100644 --- a/src/misc/simulation/settings/simulatorsettings.cpp +++ b/src/misc/simulation/settings/simulatorsettings.cpp @@ -154,6 +154,16 @@ namespace swift::misc::simulation::settings } } + void CSimulatorSettings::setPropertyModelSet(bool value) { value ? m_modelSet = true : m_modelSet = false; } + void CSimulatorSettings::setPropertyWithDbEntry(bool value) + { + value ? m_withDbEntry = true : m_withDbEntry = false; + } + void CSimulatorSettings::setPropertyDistributorFiltered(bool value) + { + value ? m_distributorFiltered = true : m_distributorFiltered = false; + } + void CSimulatorSettings::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant) { if (index.isMyself()) @@ -619,7 +629,7 @@ namespace swift::misc::simulation::settings return m_genericSettings.getModelDirectories(); } - const QStringList &CSpecializedSimulatorSettings::getDefaultModelExcludeDirectoryPatterns() const + const QStringList &CSpecializedSimulatorSettings::getDefaultModelExcludePatterns() const { return CSpecializedSimulatorSettings::defaultModelExcludeDirectoryPatterns(m_simulator); } @@ -694,8 +704,9 @@ namespace swift::misc::simulation::settings } case CSimulatorInfo::MSFS2024: { - static const QString msfs2024 = - CFileUtils::normalizeFilePathToQtStandard(CFsDirectories::msfs2024PackagesDir()); + // msfs2024 uses no model directories but uses the field "packages directory" for filtering modelstrings + // Asterix stands for everything == no filtering + static const QString msfs2024 = "*"; if (msfs2024.isEmpty()) { return e; } static const QStringList md { msfs2024 }; return md; diff --git a/src/misc/simulation/settings/simulatorsettings.h b/src/misc/simulation/settings/simulatorsettings.h index c683177b30..4aec82c37b 100644 --- a/src/misc/simulation/settings/simulatorsettings.h +++ b/src/misc/simulation/settings/simulatorsettings.h @@ -120,6 +120,11 @@ namespace swift::misc::simulation::settings //! Record GND values with radius bool setRecordedGndRadius(const swift::misc::physical_quantities::CLength &radius); + //! Reads the settings for automatic loading when starting swiftgui + bool getPropertyWithDbEntry() { return m_withDbEntry; } + bool getPropertyModelSet() { return m_modelSet; } + bool getPropertyDistributorFiltered() { return m_distributorFiltered; } + //! Reset the paths void resetPaths(); @@ -135,6 +140,10 @@ namespace swift::misc::simulation::settings //! \copydoc swift::misc::mixin::Index::setPropertyByIndex void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant); + void setPropertyModelSet(bool value); + void setPropertyWithDbEntry(bool value); + void setPropertyDistributorFiltered(bool value); + private: QString m_simulatorDirectory; //!< Simulator directory QStringList m_modelDirectories; //!< Model directory @@ -142,6 +151,11 @@ namespace swift::misc::simulation::settings bool m_comIntegration = false; //!< COM integration bool m_recordGnd = false; //!< Record GND values (of own aircraft) int m_cgSource = static_cast(CGFromSimulatorFirst); //!< CG source + bool m_modelSet = false; //!< Reads models from simulator via SimConnect (msfs2024 only) + bool m_withDbEntry = false; //!< Only models with swift database entry are used after reading (msfs2024 only) + bool m_distributorFiltered = + false; //!< Only the distributors from the configuration file are used (msfs2024 only) + physical_quantities::CLength m_recordedGndRadius { 250.0, physical_quantities::CLengthUnit::m() }; SWIFT_METACLASS( @@ -152,7 +166,10 @@ namespace swift::misc::simulation::settings SWIFT_METAMEMBER(comIntegration), SWIFT_METAMEMBER(cgSource), SWIFT_METAMEMBER(recordGnd), - SWIFT_METAMEMBER(recordedGndRadius)); + SWIFT_METAMEMBER(recordedGndRadius), + SWIFT_METAMEMBER(modelSet), + SWIFT_METAMEMBER(withDbEntry), + SWIFT_METAMEMBER(distributorFiltered)); }; //! Some P3D/FSX settings @@ -240,7 +257,7 @@ namespace swift::misc::simulation::settings const QStringList &getModelDirectoriesIfNotDefault() const; //! Default model exclude patterns - const QStringList &getDefaultModelExcludeDirectoryPatterns() const; + const QStringList &getDefaultModelExcludePatterns() const; //! First model directoy QString getFirstModelDirectoryOrDefault() const; diff --git a/src/misc/simulation/simulatedaircraft.h b/src/misc/simulation/simulatedaircraft.h index 7d8ffcd472..5dc31f20c5 100644 --- a/src/misc/simulation/simulatedaircraft.h +++ b/src/misc/simulation/simulatedaircraft.h @@ -409,6 +409,12 @@ namespace swift::misc //! Get model string const QString &getModelString() const { return m_models[CurrentModel].getModelString(); } + //! Get model Livery MSFS2024 + const QString &getLiveryString() const { return m_models[CurrentModel].getModelLivery(); } + + //! Get short model string (without livery) + const QString getShortModelString() const { return m_models[CurrentModel].getShortModelString(); } + //! Set model string void setModelString(const QString &modelString); diff --git a/src/plugins/simulator/CMakeLists.txt b/src/plugins/simulator/CMakeLists.txt index 4572f51319..17c1c40398 100644 --- a/src/plugins/simulator/CMakeLists.txt +++ b/src/plugins/simulator/CMakeLists.txt @@ -22,7 +22,7 @@ if(SWIFT_BUILD_FS9_PLUGIN OR SWIFT_BUILD_FSX_PLUGIN OR SWIFT_BUILD_P3D_PLUGIN OR add_subdirectory(fscommon) endif() -if(SWIFT_BUILD_FSX_PLUGIN OR SWIFT_BUILD_P3D_PLUGIN OR SWIFT_BUILD_MSFS_PLUGIN OR SWIFT_BUILD_MSFS2024_PLUGIN) +if(SWIFT_BUILD_FSX_PLUGIN OR SWIFT_BUILD_P3D_PLUGIN OR SWIFT_BUILD_MSFS_PLUGIN) add_subdirectory(fsxcommon) endif() diff --git a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp index 1ee57e99f0..fd273e546a 100644 --- a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp +++ b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp @@ -82,7 +82,7 @@ namespace swift::simplugin::fsxcommon hr += initSimulatorEnvironment(hSimConnect); hr += initSbDataArea(hSimConnect); if (simInfo.isMSFS()) { hr += initMSFSTransponder(hSimConnect); } - if (simInfo.isMSFS2024()) { hr += initMSFS2024Transponder(hSimConnect); } + // if (simInfo.isMSFS2024()) { hr += initMSFS2024Transponder(hSimConnect); } return hr; } @@ -423,21 +423,21 @@ namespace swift::simplugin::fsxcommon return hr; } - HRESULT CSimConnectDefinitions::initMSFS2024Transponder(const HANDLE hSimConnect) - { - HRESULT hr = s_ok(); - hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataTransponderModeMSFS, - "TRANSPONDER STATE:1", "Enum"); - hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataTransponderModeMSFS, - "TRANSPONDER IDENT:1", "Bool"); - if (isFailure(hr)) - { - CLogMessage(static_cast(nullptr)) - .error(u"SimConnect error: MSFS2024 transponder data definitions %1") - << hr; - } - return hr; - } + // HRESULT CSimConnectDefinitions::initMSFS2024Transponder(const HANDLE hSimConnect) + //{ + // HRESULT hr = s_ok(); + // hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataTransponderModeMSFS, + // "TRANSPONDER STATE:1", "Enum"); + // hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataTransponderModeMSFS, + // "TRANSPONDER IDENT:1", "Bool"); + // if (isFailure(hr)) + // { + // CLogMessage(static_cast(nullptr)) + // .error(u"SimConnect error: MSFS2024 transponder data definitions %1") + // << hr; + // } + // return hr; + // } DataDefinitionRemoteAircraftPartsWithoutLights::DataDefinitionRemoteAircraftPartsWithoutLights() { diff --git a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h index d23a3497c0..9231e8f9ce 100644 --- a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h +++ b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h @@ -262,7 +262,6 @@ namespace swift::simplugin::fsxcommon ClientAreaSquawkBox }; - // TODO TZ: are there any changes in MSFS2024 //! Handles SimConnect data definitions class FSXCOMMON_EXPORT CSimConnectDefinitions { @@ -347,7 +346,7 @@ namespace swift::simplugin::fsxcommon static HRESULT initMSFSTransponder(const HANDLE hSimConnect); //! Initialize data definition for MSFS transponder - static HRESULT initMSFS2024Transponder(const HANDLE hSimConnect); + // static HRESULT initMSFS2024Transponder(const HANDLE hSimConnect); }; } // namespace swift::simplugin::fsxcommon diff --git a/src/plugins/simulator/fsxcommon/simconnectsymbols.cpp b/src/plugins/simulator/fsxcommon/simconnectsymbols.cpp index c2f12ef4b4..3857f565d7 100644 --- a/src/plugins/simulator/fsxcommon/simconnectsymbols.cpp +++ b/src/plugins/simulator/fsxcommon/simconnectsymbols.cpp @@ -351,37 +351,6 @@ bool loadAndResolveMSFSimConnect() } } -bool loadAndResolveMSFS2024SimConnect() -{ - // Check if already loaded - if (gSymbols.SimConnect_Open) { return true; } - - QString simConnectFileName(QStringLiteral("SimConnect.MSFS2024")); - - QLibrary simConnectDll(simConnectFileName); - simConnectDll.setLoadHints(QLibrary::PreventUnloadHint); - if (simConnectDll.load()) - { - const bool resolvedCommon = resolveCommonSimConnectSymbols(simConnectDll); - if (!resolvedCommon) - { - CLogMessage(CLogCategories::driver()).error(u"Failed to resolve common symbols from SimConnect.dll: '%1'") - << simConnectFileName; - return false; - } - - CLogMessage(CLogCategories::driver()).info(u"Loaded and resolved MSFS2024 symbols from SimConnect.dll: '%1'") - << simConnectFileName; - return resolvedCommon; - } - else - { - CLogMessage(CLogCategories::driver()).error(u"Failed to load SimConnect.dll: '%1' '%2'") - << simConnectFileName << simConnectDll.errorString(); - return false; - } -} - #else bool loadAndResolveFsxSimConnect(bool manifestProbing) { diff --git a/src/plugins/simulator/fsxcommon/simconnectsymbols.h b/src/plugins/simulator/fsxcommon/simconnectsymbols.h index f8fe6c9979..1dfeef909e 100644 --- a/src/plugins/simulator/fsxcommon/simconnectsymbols.h +++ b/src/plugins/simulator/fsxcommon/simconnectsymbols.h @@ -39,7 +39,7 @@ inline bool loadAndResolveP3DSimConnectByString(const QString &version) FSXCOMMON_EXPORT bool loadAndResolveMSFSimConnect(); -FSXCOMMON_EXPORT bool loadAndResolveMSFS2024SimConnect(); +// FSXCOMMON_EXPORT bool loadAndResolveMSFS2024SimConnect(); #else diff --git a/src/plugins/simulator/fsxcommon/simconnectwindows.h b/src/plugins/simulator/fsxcommon/simconnectwindows.h index 541c1cc0fc..fd402e0cb4 100644 --- a/src/plugins/simulator/fsxcommon/simconnectwindows.h +++ b/src/plugins/simulator/fsxcommon/simconnectwindows.h @@ -17,7 +17,9 @@ // clang-format off #include -#include +//#include +#include "../third_party/externals/common/include/simconnect/P3D-v4/SimConnect.h" + // clang-format on #include diff --git a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp index e130562a6c..2e9966fdbe 100644 --- a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp +++ b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp @@ -528,7 +528,6 @@ namespace swift::simplugin::fsxcommon SIMCONNECT_PERIOD_SECOND, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED), "Cannot request title", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); - // TODO TZ use MSFS2024 FSUIPC? if (!this->getSimulatorPluginInfo().getSimulatorInfo().isMSFS() && !this->getSimulatorPluginInfo().getSimulatorInfo().isMSFS2024()) { diff --git a/src/plugins/simulator/msfs2024/CMakeLists.txt b/src/plugins/simulator/msfs2024/CMakeLists.txt index d04f639551..6b7145be32 100644 --- a/src/plugins/simulator/msfs2024/CMakeLists.txt +++ b/src/plugins/simulator/msfs2024/CMakeLists.txt @@ -7,17 +7,27 @@ add_library(simulatormsfs2024 SHARED simulatormsfs2024.json simulatormsfs2024factory.cpp simulatormsfs2024factory.h -) + simconnectsymbolsmsfs2024.cpp + simconnectsymbolsmsfs2024.h + simulatormsfs2024common.cpp + simulatormsfs2024common.h + simconnectobjectmsfs2024.cpp + simconnectobjectmsfs2024.h + simconnectdatadefinitionmsfs2024.cpp + simconnectdatadefinitionmsfs2024.h + simulatormsfs2024simconnectproc.cpp + msfs2024export.h) + set_target_properties(simulatormsfs2024 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/out/bin/plugins/simulator) set_target_properties(simulatormsfs2024 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/out/bin/plugins/simulator) target_include_directories(simulatormsfs2024 PUBLIC ${PROJECT_SOURCE_DIR}/src) +target_compile_definitions(simulatormsfs2024 PRIVATE BUILD_MSFS2024_LIB) target_link_libraries(simulatormsfs2024 PUBLIC fscommon - fsxcommon core misc Qt::Core diff --git a/src/plugins/simulator/msfs2024/msfs2024export.h b/src/plugins/simulator/msfs2024/msfs2024export.h new file mode 100644 index 0000000000..da78755089 --- /dev/null +++ b/src/plugins/simulator/msfs2024/msfs2024export.h @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright (C) 2018 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +//! \file + +#ifndef SWIFT_SIMPLUGIN_MSFS2024_SIMULATORMSFS2024_MACROS_H +#define SWIFT_SIMPLUGIN_MSFS2024_SIMULATORMSFS2024_MACROS_H + +#include + +/*! + * \def MSFS2024_EXPORT + * MSFS2024 Export Macro + */ + +#ifndef WITH_STATIC +# if defined(BUILD_MSFS2024_LIB) +# define MSFS2024_EXPORT Q_DECL_EXPORT +# else +# define MSFS2024_EXPORT Q_DECL_IMPORT +# endif +#else +# define MSFS2024_EXPORT +#endif + +#endif // SWIFT_SIMPLUGIN_MSFS2024_SIMULATORMSFS2024_MACROS_H diff --git a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp new file mode 100644 index 0000000000..7e1d45fe23 --- /dev/null +++ b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp @@ -0,0 +1,556 @@ +// SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +#include "simconnectdatadefinitionmsfs2024.h" + +#include + +#include + +#include "../fscommon/simulatorfscommonfunctions.h" +#include "simconnectsymbolsmsfs2024.h" + +#include "misc/aviation/aircraftenginelist.h" +#include "misc/aviation/aircraftparts.h" +#include "misc/logmessage.h" + +using namespace swift::misc; +using namespace swift::misc::aviation; +using namespace swift::misc::simulation; +using namespace swift::simplugin::fscommon; + +namespace swift::simplugin::msfs2024common +{ + const QString &CSimConnectDefinitions::requestToString(Request request) + { + static const QString ownAircraft("RequestOwnAircraft"); + static const QString title("RequestOwnAircraftTitle"); + static const QString livery("RequestOwnAircraftLivery"); + static const QString sbData("RequestSbData"); + static const QString facility("RequestFacility"); + static const QString end(""); + static const QString unknown("unknown"); + + switch (request) + { + case RequestOwnAircraft: return ownAircraft; + case RequestOwnAircraftTitle: return title; + case RequestSbData: return sbData; + case RequestFacility: return facility; + case RequestEndMarker: return end; + case RequestOwnAircraftLivery: return livery; + default: break; + } + return unknown; + } + + const QString &CSimConnectDefinitions::simObjectRequestToString(SimObjectRequest simObjectRequest) + { + static const QString baseId("base id"); + static const QString add("add"); + static const QString remove("remove"); + static const QString lights("lights"); + static const QString pos("position"); + static const QString model("model"); + static const QString misc("misc"); + static const QString end(""); + static const QString unknown("unknown"); + + switch (simObjectRequest) + { + case SimObjectBaseId: return baseId; + case SimObjectAdd: return add; + case SimObjectRemove: return remove; + case SimObjectLights: return lights; + case SimObjectPositionData: return pos; + case SimObjectModel: return model; + case SimObjectMisc: return misc; + case SimObjectEndMarker: return end; + default: break; + } + return unknown; + } + + CSimConnectDefinitions::CSimConnectDefinitions() {} + + HRESULT CSimConnectDefinitions::initDataDefinitionsWhenConnected(const HANDLE hSimConnect, + const CSimulatorInfo &simInfo) + { + Q_UNUSED(simInfo); + + HRESULT hr = s_ok(); + hr += initOwnAircraft(hSimConnect); + hr += initRemoteAircraft(hSimConnect); + hr += initRemoteAircraftSimData(hSimConnect); + hr += initRemoteAircraftSimDataSet(hSimConnect); + hr += initSimulatorEnvironment(hSimConnect); + hr += initSbDataArea(hSimConnect); + hr += initMSFS2024Transponder(hSimConnect); + hr += initOwnAircraftList(hSimConnect); + return hr; + } + + HRESULT CSimConnectDefinitions::initOwnAircraft(const HANDLE hSimConnect) + { + // MSFS2024 vars: + // https://docs.flightsimulator.com/msfs2024/html/6_Programming_APIs/SimVars/Simulation_Variables.htm + HRESULT hr = s_ok(); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PLANE LATITUDE", + "Degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PLANE LONGITUDE", + "Degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PLANE ALTITUDE", + "Feet"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "PLANE ALT ABOVE GROUND", "Feet"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PRESSURE ALTITUDE", + "Meters"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "STATIC CG TO GROUND", "Feet"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "PLANE HEADING DEGREES TRUE", "Degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "PLANE PITCH DEGREES", "Degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "PLANE BANK DEGREES", + "Degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "GROUND VELOCITY", + "Knots"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "GROUND ALTITUDE", + "Feet"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "SIM ON GROUND", + "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT STROBE", + "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT LANDING", + "Bool"); + hr += + SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT TAXI", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT BEACON", + "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT NAV", "Bool"); + hr += + SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT LOGO", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "TRANSPONDER CODE:1", + nullptr); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "COM ACTIVE FREQUENCY:1", "MHz"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "COM ACTIVE FREQUENCY:2", "MHz"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "COM STANDBY FREQUENCY:1", "MHz"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "COM STANDBY FREQUENCY:2", "MHz"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "COM TRANSMIT:1", + "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "COM TRANSMIT:2", + "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "COM RECEIVE ALL", + "Bool"); + hr += + SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "COM TEST:1", "Bool"); + hr += + SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "COM TEST:2", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "COM STATUS:1", + "Enum"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "COM STATUS:2", + "Enum"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "FLAPS HANDLE PERCENT", "Percent Over 100"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "SPOILERS HANDLE POSITION", "Percent Over 100"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "GEAR HANDLE POSITION", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "NUMBER OF ENGINES", + "Number"); + // Simconnect supports index 1 - 4 + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "GENERAL ENG COMBUSTION:1", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "GENERAL ENG COMBUSTION:2", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "GENERAL ENG COMBUSTION:3", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "GENERAL ENG COMBUSTION:4", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "VELOCITY WORLD X", + "Feet per second"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "VELOCITY WORLD Y", + "Feet per second"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "VELOCITY WORLD Z", + "Feet per second"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "ROTATION VELOCITY BODY X", "Radians per second"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "ROTATION VELOCITY BODY Y", "Radians per second"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "ROTATION VELOCITY BODY Z", "Radians per second"); + // FS2020 + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "INDICATED ALTITUDE CALIBRATED", "Feet"); + + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraftTitle, "TITLE", + nullptr, SIMCONNECT_DATATYPE_STRING256); + // MSFS2024 specific from here + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraftTitle, "LIVERY NAME", + nullptr, SIMCONNECT_DATATYPE_STRING256); + + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)).error(u"SimConnect error: initOwnAircraft %1") + << hr; + } + return hr; + } + + HRESULT CSimConnectDefinitions::initRemoteAircraft(const HANDLE hSimConnect) + { + HRESULT hr = s_ok(); + // Position + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetPosition, + "Initial Position", nullptr, SIMCONNECT_DATATYPE_INITPOSITION); + + // Hint: "Bool" and "Percent .." are units name + // default data type is SIMCONNECT_DATATYPE_FLOAT64 -> double + + // Flaps + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "LEADING EDGE FLAPS LEFT PERCENT", "Percent Over 100"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "LEADING EDGE FLAPS RIGHT PERCENT", "Percent Over 100"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "TRAILING EDGE FLAPS LEFT PERCENT", "Percent Over 100"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "TRAILING EDGE FLAPS RIGHT PERCENT", "Percent Over 100"); + + // Gear & Spoiler + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "GEAR HANDLE POSITION", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "SPOILERS HANDLE POSITION", "Percent Over 100"); + + // Engines + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "GENERAL ENG COMBUSTION:1", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "GENERAL ENG COMBUSTION:2", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "GENERAL ENG COMBUSTION:3", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "GENERAL ENG COMBUSTION:4", "Bool"); + + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraftTitle, "TITLE", + nullptr, SIMCONNECT_DATATYPE_STRING256); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraftTitle, "LIVERY NAME", + nullptr, SIMCONNECT_DATATYPE_STRING256); + + // Lights (other definition) + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, + "LIGHT STROBE", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, + "LIGHT LANDING", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, + "LIGHT TAXI", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, + "LIGHT BEACON", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, "LIGHT NAV", + "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, + "LIGHT LOGO", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, "LIGHT NAV", + "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, + "LIGHT RECOGNITION", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, + "LIGHT CABIN", "Bool"); + + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: initRemoteAircraftSituation %1") + << hr; + } + return hr; + } + + HRESULT CSimConnectDefinitions::initRemoteAircraftSimData(const HANDLE hSimConnect) + { + HRESULT hr = s_ok(); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftGetPosition, + "PLANE LATITUDE", "degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftGetPosition, + "PLANE LONGITUDE", "degrees"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftGetPosition, + "PLANE ALTITUDE", "Feet"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftGetPosition, + "GROUND ALTITUDE", "Feet"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftGetPosition, + "STATIC CG TO GROUND", "Feet"); + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: initRemoteAircraftSimData DataRemoteAircraftGetPosition %1") + << hr; + } + + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftModelData, + "STATIC CG TO GROUND", "Feet"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftModelData, + "ATC TYPE", nullptr, SIMCONNECT_DATATYPE_STRING32); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftModelData, + "ATC MODEL", nullptr, SIMCONNECT_DATATYPE_STRING32); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftModelData, "ATC ID", + nullptr, SIMCONNECT_DATATYPE_STRING32); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftModelData, + "ATC AIRLINE", nullptr, SIMCONNECT_DATATYPE_STRING64); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftModelData, + "ATC FLIGHT NUMBER", nullptr, SIMCONNECT_DATATYPE_STRING8); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftModelData, "TITLE", + nullptr, SIMCONNECT_DATATYPE_STRING256); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftModelData, + "LIVERY NAME", nullptr, SIMCONNECT_DATATYPE_STRING256); + + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: initRemoteAircraftSimData DataRemoteAircraftModelData %1") + << hr; + } + return hr; + } + + HRESULT CSimConnectDefinitions::initRemoteAircraftSimDataSet(const HANDLE hSimConnect) + { + HRESULT hr = s_ok(); + + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetData, "ATC ID", + nullptr, SIMCONNECT_DATATYPE_STRING32); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetData, + "ATC AIRLINE", nullptr, SIMCONNECT_DATATYPE_STRING64); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetData, + "ATC FLIGHT NUMBER", nullptr, SIMCONNECT_DATATYPE_STRING8); + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: initRemoteAircraftSimDataSet DataRemoteAircraftModelData %1") + << hr; + } + return hr; + } + + HRESULT CSimConnectDefinitions::initSimulatorEnvironment(const HANDLE hSimConnect) + { + HRESULT hr = s_ok(); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataSimEnvironment, "ZULU TIME", "", + SIMCONNECT_DATATYPE_INT32); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataSimEnvironment, "ZULU YEAR", "", + SIMCONNECT_DATATYPE_INT32); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataSimEnvironment, + "ZULU MONTH OF YEAR", "", SIMCONNECT_DATATYPE_INT32); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataSimEnvironment, + "ZULU DAY OF MONTH", "", SIMCONNECT_DATATYPE_INT32); + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: initSimulatorEnvironment %1") + << hr; + } + return hr; + } + + HRESULT CSimConnectDefinitions::initSbDataArea(const HANDLE hSimConnect) + { + HRESULT hr = s_ok(); + const DWORD sbSize = sizeof(DataDefinitionClientAreaSb); + + // We need to know the client area 'name' and map it to a client ID + hr += SimConnect_MapClientDataNameToID(hSimConnect, "SquawkBox Data", ClientAreaSquawkBox); + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: SimConnect_MapClientDataNameToID %1") + << hr; + return hr; + } + + // Mapping needs to be first + hr += SimConnect_CreateClientData(hSimConnect, ClientAreaSquawkBox, sbSize, + SIMCONNECT_CREATE_CLIENT_DATA_FLAG_DEFAULT); + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: SimConnect_CreateClientData %1") + << hr; + return hr; + } + + // data definitions + hr += SimConnect_AddToClientDataDefinition(hSimConnect, CSimConnectDefinitions::DataClientAreaSb, 0, + sbSize); // whole area + hr += SimConnect_AddToClientDataDefinition(hSimConnect, CSimConnectDefinitions::DataClientAreaSbStandby, 17, + 1); // standby + hr += SimConnect_AddToClientDataDefinition(hSimConnect, CSimConnectDefinitions::DataClientAreaSbIdent, 19, + 1); // ident + hr += SimConnect_AddToClientDataDefinition(hSimConnect, CSimConnectDefinitions::DataClientAreaSbConnected, 1, + 1); // network connected + hr += SimConnect_AddToClientDataDefinition(hSimConnect, CSimConnectDefinitions::DataClientAreaSbRunning, 0, + 1); // SB running + + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: SB data area data definitions %1") + << hr; + return hr; + } + + // write a default client area so we are not suddenly squawking ident or so + DataDefinitionClientAreaSb sbArea; + byte sbRunning = 1; + sbArea.setDefaultValues(); + hr += SimConnect_SetClientData(hSimConnect, ClientAreaSquawkBox, CSimConnectDefinitions::DataClientAreaSb, + SIMCONNECT_CLIENT_DATA_SET_FLAG_DEFAULT, 0, sbSize, &sbArea); + hr += + SimConnect_SetClientData(hSimConnect, ClientAreaSquawkBox, CSimConnectDefinitions::DataClientAreaSbRunning, + SIMCONNECT_CLIENT_DATA_SET_FLAG_DEFAULT, 0, 1, &sbRunning); + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: SimConnect_SetClientData %1") + << hr; + } + return hr; + } + + HRESULT CSimConnectDefinitions::initMSFS2024Transponder(const HANDLE hSimConnect) + { + HRESULT hr = s_ok(); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataTransponderModeMSFS, + "TRANSPONDER STATE:1", "Enum"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataTransponderModeMSFS, + "TRANSPONDER IDENT:1", "Bool"); + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: MSFS2024 transponder data definitions %1") + << hr; + } + return hr; + } + + HRESULT CSimConnectDefinitions::initOwnAircraftList(const HANDLE hSimConnect) + { + // MSFS2024 vars: + // https://docs.flightsimulator.com/msfs2024/html/6_Programming_APIs/SimVars/Simulation_Variables.htm + HRESULT hr = s_ok(); + hr += SimConnect_EnumerateSimObjectsAndLiveries(hSimConnect, CSimConnectDefinitions::REQUEST_AIRPLANE, + SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT); + hr += SimConnect_EnumerateSimObjectsAndLiveries(hSimConnect, CSimConnectDefinitions::REQUEST_HELICOPTER, + SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT); + // hr += SimConnect_EnumerateSimObjectsAndLiveries(hSimConnect, CSimConnectDefinitions::REQUEST_HOT_AIR, + // SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT); + + if (isFailure(hr)) + { + CLogMessage(static_cast(nullptr)) + .error(u"SimConnect error: initOwnAircraftList %1") + << hr; + } + return hr; + } + + DataDefinitionRemoteAircraftPartsWithoutLights::DataDefinitionRemoteAircraftPartsWithoutLights() + { + this->resetToInvalid(); + } + + DataDefinitionRemoteAircraftPartsWithoutLights::DataDefinitionRemoteAircraftPartsWithoutLights( + const CAircraftParts &parts) + { + this->initFromParts(parts); + } + + bool DataDefinitionRemoteAircraftPartsWithoutLights::operator==( + const DataDefinitionRemoteAircraftPartsWithoutLights &rhs) const + { + return std::tie(flapsLeadingEdgeLeftPercent, flapsLeadingEdgeRightPercent, flapsTrailingEdgeLeftPercent, + flapsTrailingEdgeRightPercent, gearHandlePosition, spoilersHandlePosition, engine1Combustion, + engine2Combustion, engine3Combustion, engine4Combustion) == + std::tie(rhs.flapsLeadingEdgeLeftPercent, rhs.flapsLeadingEdgeRightPercent, + rhs.flapsTrailingEdgeLeftPercent, rhs.flapsTrailingEdgeRightPercent, rhs.gearHandlePosition, + rhs.spoilersHandlePosition, rhs.engine1Combustion, rhs.engine2Combustion, rhs.engine3Combustion, + rhs.engine4Combustion); + } + + void DataDefinitionRemoteAircraftPartsWithoutLights::setAllEngines(bool on) + { + engine1Combustion = on ? 1 : 0; + engine2Combustion = on ? 1 : 0; + engine3Combustion = on ? 1 : 0; + engine4Combustion = on ? 1 : 0; + } + + void DataDefinitionRemoteAircraftPartsWithoutLights::setEngine(int number1based, bool on) + { + double v = on ? 1.0 : 0.0; + switch (number1based) + { + case 1: engine1Combustion = v; break; + case 2: engine2Combustion = v; break; + case 3: engine3Combustion = v; break; + case 4: engine4Combustion = v; break; + default: break; + } + } + + void DataDefinitionRemoteAircraftPartsWithoutLights::resetAllFlaps() + { + flapsLeadingEdgeLeftPercent = 0.0; + flapsLeadingEdgeRightPercent = 0.0; + flapsTrailingEdgeLeftPercent = 0.0; + flapsTrailingEdgeRightPercent = 0.0; + } + + void DataDefinitionRemoteAircraftPartsWithoutLights::resetSpoilers() { spoilersHandlePosition = 0.0; } + + void DataDefinitionRemoteAircraftPartsWithoutLights::resetToInvalid() + { + flapsLeadingEdgeLeftPercent = -1; + flapsLeadingEdgeRightPercent = -1; + flapsTrailingEdgeLeftPercent = -1; + flapsTrailingEdgeRightPercent = -1; + gearHandlePosition = -1; + spoilersHandlePosition = -1; + engine1Combustion = -1; + engine2Combustion = -1; + engine3Combustion = -1; + engine4Combustion = -1; + } + + void DataDefinitionRemoteAircraftPartsWithoutLights::initFromParts(const CAircraftParts &parts) + { + gearHandlePosition = parts.isFixedGearDown() ? 1.0 : 0.0; + const double trail = parts.getFlapsPercent() / 100.0; + const double lead = trail; + flapsTrailingEdgeLeftPercent = trail; + flapsTrailingEdgeRightPercent = trail; + flapsLeadingEdgeLeftPercent = lead; + flapsLeadingEdgeRightPercent = lead; + spoilersHandlePosition = parts.isSpoilersOut() ? 1.0 : 0.0; + this->setAllEngines(false); // init + + int e = 1; + for (const CAircraftEngine &engine : parts.getEngines()) { this->setEngine(e++, engine.isOn()); } + } + + CAircraftLights DataDefinitionRemoteAircraftLights::toLights() const + { + return CAircraftLights(dtb(lightStrobe), dtb(lightLanding), dtb(lightTaxi), dtb(lightBeacon), dtb(lightNav), + dtb(lightLogo), dtb(lightRecognition), dtb(lightCabin)); + } + + QString DataDefinitionClientAreaSb::toQString() const + { + return u"0 (running): " % QString::number(data[0]) % u" 1 (connected): " % QString::number(data[1]) % + u" 17 (standby): " % QString::number(data[17]) % u" 19 (ident): " % QString::number(data[19]); + } + +} // namespace swift::simplugin::msfs2024common diff --git a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h new file mode 100644 index 0000000000..1c2bd4571d --- /dev/null +++ b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h @@ -0,0 +1,383 @@ +// 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_SIMCONNECT_DATADEFINITION_H +#define SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMCONNECT_DATADEFINITION_H + +#include + +#include +#include + +#include "misc/aviation/aircraftlights.h" +#include "misc/simulation/simulatorinfo.h" +#include "plugins/simulator/msfs2024/msfs2024export.h" +#include "plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.h" +#include "plugins/simulator/msfs2024/simconnectwindowsmsfs2024.h" + +namespace swift::misc::aviation +{ + class CAircraftParts; +} +namespace swift::simplugin::msfs2024common +{ + //! Data struct of our own aircraft + //! \sa SimConnect variables http://msdn.microsoft.com/en-us/library/cc526981.aspx + //! \sa SimConnect events http://msdn.microsoft.com/en-us/library/cc526980.aspx + struct DataDefinitionOwnAircraft + { + double latitudeDeg; //!< Latitude (deg) + double longitudeDeg; //!< Longitude (deg) + double altitudeFt; //!< Altitude (ft) + double altitudeAGLFt; //!< Altitude above ground (ft) + double pressureAltitudeM; //!< Pressure altitude (m) + double cgToGroundFt; //!< Static CG to ground (ft) + double trueHeadingDeg; //!< True heading (deg) + double pitchDeg; //!< Pitch (deg) + double bankDeg; //!< Bank (deg) + double velocity; //!< Ground velocity + double elevationFt; //!< Elevation (ft) + double simOnGround; //!< Is aircraft on ground? + // 12 + double lightStrobe; //!< Is strobe light on? + double lightLanding; //!< Is landing light on? + double lightTaxi; //!< Is taxi light on? + double lightBeacon; //!< Is beacon light on? + double lightNav; //!< Is nav light on? + double lightLogo; //!< Is logo light on? + // 18 + double transponderCode; //!< Transponder Code + double com1ActiveMHz; //!< COM1 active frequency + double com2ActiveMHz; //!< COM2 active frequency + double com1StandbyMHz; //!< COM1 standby frequency + double com2StandbyMHz; //!< COM2 standby frequency + double comTransmit1; //!< COM1 transmit, means also receiving + double comTransmit2; //!< COM2 transmit, means also receiving + double comReceiveAll; //!< all COMs receiving, or COM:x transmitting or receiving + double comTest1; //!< COM1 test + double comTest2; //!< COM2 test + double comStatus1; //!< COM1 status + double comStatus2; //!< COM2 status + // 30 + double flapsHandlePosition; //!< Flaps handle position in percent + double spoilersHandlePosition; //!< Spoilers out? (flag) + double gearHandlePosition; //!< Gear handle position (flag) + // 33 + double numberOfEngines; //!< Number of engines + double engine1Combustion; //!< Engine 1 combustion flag + double engine2Combustion; //!< Engine 2 combustion flag + double engine3Combustion; //!< Engine 3 combustion flag + double engine4Combustion; //!< Engine 4 combustion flag + // 38 + double velocityWorldX; //!< Velocity World X + double velocityWorldY; //!< Velocity World Y + double velocityWorldZ; //!< Velocity World Z + double rotationVelocityBodyX; //!< Rotation Velocity Body X + double rotationVelocityBodyY; //!< Rotation Velocity Body Y + double rotationVelocityBodyZ; //!< Rotation Velocity Body Z + // 44 + double altitudeCalibratedFt; //!< Altitude without temperature effect (ft, FS2020) + // 45 + }; + + //! Data struct of aircraft position + struct DataDefinitionOwnAircraftModel + { + char title[256]; //!< Aircraft model string + char livery[256]; //!< Aircraft model string + }; + + //! Data struct of aircraft model data + + // struct DataDefinitionOwnAircraftLivery + //{ + // char livery[256]; //!< Aircraft model string + // }; + + ////! Data struct of aircraft model livery + + struct DataDefinitionRemoteAircraftModel + { + double cgToGroundFt; //!< Static CG to ground (ft) + char atcType[32]; //!< type + char atcModel[32]; //!< model + char atcId[32]; //!< id + char atcAirlineNumber[64]; //!< airline number + char atcFlightNumber[8]; //!< flight number (168) + char title[256]; //!< Aircraft model string + }; + + //! Data struct of aircraft data (setable) + struct DataDefinitionRemoteAtc + { + // length here is from SimConnect_AddToDataDefinition + char atcId[32]; //!< ID used by ATC + char atcAirline[64]; //!< Airline used by ATC + char atcFlightNumber[8]; //!< Flight Number used by ATC + + //! @{ + //! Copy the strings, length from docu + void copyAtcId(const char *c) + { + strncpy_s(atcId, c, 10); + atcId[9] = 0; + } + void copyAtcAirline(const char *c) + { + strncpy_s(atcAirline, c, 50); + atcAirline[49] = 0; + } + void copyFlightNumber(const char *c) + { + strncpy_s(atcFlightNumber, c, 6); + atcFlightNumber[5] = 0; + } + //! @} + + //! Set default values + void setDefaultValues() + { + std::fill(atcId, atcId + 10, static_cast(0)); + std::fill(atcAirline, atcAirline + 50, static_cast(0)); + std::fill(atcFlightNumber, atcFlightNumber + 6, static_cast(0)); + } + }; + + //! Data struct of remote aircraft parts + struct MSFS2024_EXPORT DataDefinitionRemoteAircraftPartsWithoutLights + { + double flapsLeadingEdgeLeftPercent; //!< Leading edge left in percent 0..1 + double flapsLeadingEdgeRightPercent; //!< Leading edge right in percent 0..1 + double flapsTrailingEdgeLeftPercent; //!< Trailing edge left in percent 0..1 + double flapsTrailingEdgeRightPercent; //!< Trailing edge right in percent 0..1 + double gearHandlePosition; //!< Gear handle position + double spoilersHandlePosition; //!< Spoilers out? + double engine1Combustion; //!< Engine 1 combustion flag + double engine2Combustion; //!< Engine 2 combustion flag + double engine3Combustion; //!< Engine 3 combustion flag + double engine4Combustion; //!< Engine 4 combustion flag + + //! Ctor + DataDefinitionRemoteAircraftPartsWithoutLights(); + + //! Ctor + DataDefinitionRemoteAircraftPartsWithoutLights(const swift::misc::aviation::CAircraftParts &parts); + + //! Equal to other parts + bool operator==(const DataDefinitionRemoteAircraftPartsWithoutLights &rhs) const; + + //! All engines on/off + void setAllEngines(bool on); + + //! Set given engine + void setEngine(int number1based, bool on); + + //! Reset all flaps + void resetAllFlaps(); + + //! Reset spoilers + void resetSpoilers(); + + //! Reset to invalid values + void resetToInvalid(); + + //! Init from parts + void initFromParts(const swift::misc::aviation::CAircraftParts &parts); + }; + + //! Data for aircraft lighs + struct MSFS2024_EXPORT DataDefinitionRemoteAircraftLights + { + double lightStrobe; //!< Is strobe light on? + double lightLanding; //!< Is landing light on? + double lightTaxi; //!< Is taxi light on? + double lightBeacon; //!< Is beacon light on? + double lightNav; //!< Is nav light on? + double lightLogo; //!< Is logo light on? + double lightRecognition; //!< Is recognition light on + double lightCabin; //!< Is cabin light on + + //! Convert to lights + swift::misc::aviation::CAircraftLights toLights() const; + }; + + //! Data for AI object and probe sent back from simulator + struct DataDefinitionPosData + { + double latitudeDeg; //!< Latitude (deg) + double longitudeDeg; //!< Longitude (deg) + double altitudeFt; //!< Altitude (ft) + double elevationFt; //!< Elevation (ft) + double cgToGroundFt; //!< Static CG to ground (ft) + + //! Above ground ft + double aboveGroundFt() const { return altitudeFt - elevationFt; } + + //! Above ground ft + bool isOnGround() const { return this->aboveGroundFt() < 1.0; } + }; + + //! 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 + struct DataDefinitionClientAreaSb + { + byte data[128] {}; //!< 128 bytes of data, offsets + + //! Standby = 1, else 0 + byte getTransponderMode() const { return data[17]; } + + //! Ident = 1, else 0 + byte getIdent() const { return data[19]; } + + //! Ident? + bool isIdent() const { return getIdent() != 0; } + + //! Standby + bool isStandby() const { return getTransponderMode() != 0; } + + //! SB is running + void setRunning(bool running) { data[0] = running ? 1 : 0; } + + //! Mark as connected with network + void setConnected(bool connected) { data[1] = connected ? 1 : 0; } + + //! Set default values + void setDefaultValues() + { + std::fill(data, data + 128, static_cast(0)); + data[0] = 1; // SB running, indicates the client is running as external app, 0..not running, 1..external + // app, 2..FS module + data[1] = 0; // SB connected to FSD, 0..not connected, 1..connected + data[17] = 1; // 1..standby, 0..mode C + data[19] = 0; // no ident + } + + //! Values + QString toQString() const; + }; + + //! Data structure for MSFS transponder mode information + struct DataDefinitionMSFSTransponderMode + { + double transponderMode = 1; //!< transponder state simvar + double ident = 0; //!< ident + }; + + //! Client areas + enum ClientAreaId + { + ClientAreaSquawkBox + }; + + //! Handles SimConnect data definitions for MSFS2024 + class MSFS2024_EXPORT CSimConnectDefinitions + { + public: + //! SimConnect definiton IDs + enum DataDefiniton + { + DataOwnAircraft, + DataOwnAircraftTitle, + DataRemoteAircraftLights, + DataRemoteAircraftPartsWithoutLights, + DataRemoteAircraftSetPosition, //!< the position which will be set + DataRemoteAircraftGetPosition, //!< get position to evaluate altitude / AGL + DataRemoteAircraftModelData, //!< model data eventually used and reported back from simulator + DataRemoteAircraftSetData, //!< set model data such as airline + DataSimEnvironment, + DataTransponderModeMSFS, + DataClientAreaSb, //!< whole SB area, see http://squawkbox.ca/doc/sdk/fsuipc.php + DataClientAreaSbIdent, //!< SB ident single value 0x7b93/19 + DataClientAreaSbStandby, //!< SB standby 0x7b91/17 + DataClientAreaSbConnected, //!< SB connected with network 0x7b81/1 + DataClientAreaSbRunning //!< SB running 0x7b80/0 + }; + + //! SimConnect request IDs + enum Request + { + RequestOwnAircraft, + RequestOwnAircraftTitle, + RequestOwnAircraftLivery, + RequestSbData, //!< SB client area / XPDR mode + RequestMSFSTransponder, //!< MSFS XPDR mode/ident + RequestFacility, + RequestEndMarker, //!< free request ids can start here + + }; + + //! SimObject requests used for AI aircraft and probes + enum SimObjectRequest + { + SimObjectBaseId, //!< base id without specific request + SimObjectAdd, + SimObjectRemove, + SimObjectPositionData, + SimObjectLights, + SimObjectModel, + SimObjectMisc, + SimObjectEndMarker //!< end marker, do NOT remove, also means invalid + }; + + enum REQUEST_ID + { + REQUEST_NONE = 0, + REQUEST_POSITION_USER = 50, + REQUEST_CREATE = 100, + REQUEST_ALL = 1000, + REQUEST_USER, + REQUEST_AIRPLANE, + REQUEST_HELICOPTER, + REQUEST_GROUND, + REQUEST_ANIMAL, + REQUEST_HOT_AIR, + REQUEST_BOAT, + }; + + //! Request to string + static const QString &requestToString(Request request); + + //! Request to string + static const QString &simObjectRequestToString(SimObjectRequest simObjectRequest); + + //! Constructor + CSimConnectDefinitions(); + + //! Initialize all data definitions + static HRESULT initDataDefinitionsWhenConnected(const HANDLE hSimConnect, + const swift::misc::simulation::CSimulatorInfo &simInfo); + + //! Initialize data retrieval for model list + static HRESULT initOwnAircraftList(const HANDLE hSimConnect); + + private: + //! Initialize data definition for our own aircraft + static HRESULT initOwnAircraft(const HANDLE hSimConnect); + + //! Initialize data definition for remote aircraft + static HRESULT initRemoteAircraft(const HANDLE hSimConnect); + + //! Initialize data for setting remote aircraft airline etc. + static HRESULT initRemoteAircraftSimData(const HANDLE hSimConnect); + + //! Initialize data for remote aircraft queried from simulator + static HRESULT initRemoteAircraftSimDataSet(const HANDLE hSimConnect); + + //! Initialize data definition for Simulator environment + static HRESULT initSimulatorEnvironment(const HANDLE hSimConnect); + + //! Initialize the SB data are + static HRESULT initSbDataArea(const HANDLE hSimConnect); + + //! Initialize data definition for MSFS transponder + // static HRESULT initMSFSTransponder(const HANDLE hSimConnect); + + //! Initialize data definition for MSFS transponder + static HRESULT initMSFS2024Transponder(const HANDLE hSimConnect); + }; +} // namespace swift::simplugin::msfs2024common + +#endif // SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMCONNECT_DATADEFINITION_H diff --git a/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.cpp b/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.cpp new file mode 100644 index 0000000000..1d2251fe5b --- /dev/null +++ b/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.cpp @@ -0,0 +1,547 @@ +// SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +#include "simconnectobjectmsfs2024.h" + +#include "simulatormsfs2024common.h" + +#include "config/buildconfig.h" +#include "core/simulator.h" +#include "misc/simulation/interpolation/interpolatormulti.h" +#include "misc/stringutils.h" + +using namespace swift::config; +using namespace swift::misc; +using namespace swift::misc::aviation; +using namespace swift::misc::simulation; +using namespace swift::core; + +namespace swift::simplugin::msfs2024common +{ + CSimConnectObject::CSimConnectObject() { this->resetCameraPositions(); } + + CSimConnectObject::CSimConnectObject(CSimConnectObject::SimObjectType type) : m_type(type) + { + this->resetCameraPositions(); + } + + CSimConnectObject::CSimConnectObject(const CSimulatedAircraft &aircraft, DWORD requestId, + ISimulationEnvironmentProvider *simEnvProvider, + IInterpolationSetupProvider *setupProvider, + IRemoteAircraftProvider *remoteAircraftProvider, CInterpolationLogger *logger) + : m_aircraft(aircraft), m_requestId(requestId), m_validRequestId(true), + m_interpolator(QSharedPointer::create(aircraft.getCallsign(), simEnvProvider, + setupProvider, remoteAircraftProvider, logger)) + { + this->resetCameraPositions(); + m_type = aircraft.isTerrainProbe() ? TerrainProbe : AircraftNonAtc; + m_interpolator->initCorrespondingModel(aircraft.getModel()); + m_callsignByteArray = aircraft.getCallsignAsString().toLatin1(); + } + + void CSimConnectObject::setAircraft(const CSimulatedAircraft &aircraft) + { + m_aircraft = aircraft; + m_callsignByteArray = aircraft.getCallsignAsString().toLatin1(); + m_type = aircraft.isTerrainProbe() ? TerrainProbe : AircraftNonAtc; + } + + void CSimConnectObject::setAircraftModelString(const QString &modelString) + { + if (modelString.isEmpty()) { return; } + m_aircraft.setModelString(modelString); + } + + void CSimConnectObject::setAircraftCG(const physical_quantities::CLength &cg) + { + if (cg.isNull()) { return; } + m_aircraft.setCG(cg); + } + + void CSimConnectObject::setRequestId(DWORD id) + { + m_requestId = id; + m_validRequestId = true; + const SimObjectType type = requestIdToType(id); + this->setType(type); + } + + DWORD CSimConnectObject::getRequestId(CSimConnectDefinitions::SimObjectRequest offset) const + { + if (CBuildConfig::isLocalDeveloperDebugBuild()) + { + const SimObjectType type = requestIdToType(m_requestId); + const bool same = CSimConnectObject::isSameTypeGroup(type, this->getType()); + Q_ASSERT_X(same, Q_FUNC_INFO, "Type mismatch"); + } + + DWORD os = 0; + switch (this->getType()) + { + case TerrainProbe: os = static_cast(CSimulatorMsfs2024::offsetSimObjTerrainProbe(offset)); break; + case AircraftNonAtc: + case AircraftSimulatedObject: + default: os = static_cast(CSimulatorMsfs2024::offsetSimObjAircraft(offset)); break; + } + return os + m_requestId; + } + + void CSimConnectObject::setObjectId(DWORD id) + { + m_objectId = id; + m_validObjectId = true; + } + + bool CSimConnectObject::isPendingAdded() const { return !this->hasValidRequestAndObjectId() || !m_confirmedAdded; } + + bool CSimConnectObject::isOutdatedPendingAdded(qint64 thresholdMs, qint64 currentMsSinceEpoch) const + { + if (!this->isPendingAdded()) { return false; } + if (currentMsSinceEpoch < 0) { currentMsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); } + if (m_tsCreated < 0) { return true; } // no valid timestamp + const qint64 delta = currentMsSinceEpoch - m_tsCreated; + return delta > thresholdMs; + } + + bool CSimConnectObject::isConfirmedAdded() const + { + Q_ASSERT_X(!m_confirmedAdded || this->hasValidRequestAndObjectId(), Q_FUNC_INFO, "confirmed but invalid ids"); + return m_confirmedAdded; + } + + void CSimConnectObject::setConfirmedAdded(bool confirm) + { + m_confirmedAdded = confirm; + m_removedWhileAdding = false; + m_addedWhileRemoving = false; + m_aircraft.setRendered(true); + } + + void CSimConnectObject::setAddedWhileRemoving(bool addedWileRemoved) { m_addedWhileRemoving = addedWileRemoved; } + + void CSimConnectObject::setRemovedWhileAdding(bool removedWhileAdding) + { + m_removedWhileAdding = removedWhileAdding; + } + + bool CSimConnectObject::isReadyToSend() const + { + return !this->isPending() && !m_addedWhileRemoving && !m_removedWhileAdding; + } + + void CSimConnectObject::setPendingRemoved(bool pending) + { + m_pendingRemoved = pending; + m_removedWhileAdding = false; + m_addedWhileRemoving = false; + m_aircraft.setRendered(false); + } + + void CSimConnectObject::resetCameraPositions() + { + m_cameraPosition.x = 0; + m_cameraPosition.y = 0; + m_cameraPosition.z = 0; + m_cameraRotation.Pitch = 0; + m_cameraRotation.Bank = 0; + m_cameraRotation.Heading = 0; + } + + void CSimConnectObject::resetState() + { + m_pendingRemoved = false; + m_confirmedAdded = false; + m_removedWhileAdding = false; + m_addedWhileRemoving = false; + m_camera = false; + m_currentLightsInSim = CAircraftLights(); + m_lightsAsSent = CAircraftLights(); + m_requestId = 0; + m_objectId = 0; + m_addingExceptions = 0; + m_validRequestId = false; + m_validObjectId = false; + m_tsCreated = -1; + this->resetCameraPositions(); + } + + void CSimConnectObject::resetToAddAgain() + { + const CSimConnectObject old(*this); + this->resetState(); + this->copyAddingFailureCounters(old); + } + + bool CSimConnectObject::hasValidRequestAndObjectId() const + { + return this->hasValidRequestId() && this->hasValidObjectId(); + } + + void CSimConnectObject::copyAddingFailureCounters(const CSimConnectObject &otherObject) + { + m_addingExceptions = otherObject.m_addingExceptions; + m_addingDirectlyRemoved = otherObject.m_addingDirectlyRemoved; + } + + QString CSimConnectObject::getInterpolatorInfo(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const + { + Q_ASSERT(m_interpolator); + return m_interpolator->getInterpolatorInfo(mode); + } + + void CSimConnectObject::attachInterpolatorLogger(CInterpolationLogger *logger) const + { + Q_ASSERT(m_interpolator); + m_interpolator->attachLogger(logger); + } + + CInterpolationResult CSimConnectObject::getInterpolation(qint64 currentTimeSinceEpoch, + const CInterpolationAndRenderingSetupPerCallsign &setup, + uint32_t aircraftNumber) const + { + if (!m_interpolator) { return {}; } + return m_interpolator->getInterpolation(currentTimeSinceEpoch, setup, aircraftNumber); + } + + const CAircraftSituation & + CSimConnectObject::getLastInterpolatedSituation(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const + { + if (!m_interpolator) { return CAircraftSituation::null(); } + return m_interpolator->getLastInterpolatedSituation(mode); + } + + const CStatusMessageList & + CSimConnectObject::getInterpolationMessages(CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const + { + static const CStatusMessageList empty; + if (!m_interpolator) { return empty; } + return m_interpolator->getInterpolationMessages(mode); + } + + QString CSimConnectObject::toQString() const + { + static const QString s( + "CS: '%1' obj: %2 req: %3 conf.added: %4 pend.rem.: %5 rwa: %6 awr: %7 aEx: %8 aRem: %9"); + return s.arg(this->getCallsign().asString()) + .arg(m_objectId) + .arg(m_requestId) + .arg(boolToYesNo(m_confirmedAdded), boolToYesNo(m_pendingRemoved), boolToYesNo(m_removedWhileAdding), + boolToYesNo(m_addedWhileRemoving)) + .arg(m_addingExceptions) + .arg(m_addingDirectlyRemoved); + } + + CSimConnectObject::SimObjectType CSimConnectObject::requestIdToType(DWORD requestId) + { + if (CSimulatorMsfs2024::isRequestForSimObjTerrainProbe(requestId)) { return TerrainProbe; } + if (CSimulatorMsfs2024::isRequestForSimObjAircraft(requestId)) { return AircraftNonAtc; } + Q_ASSERT_X(false, Q_FUNC_INFO, "Wrong range"); + return AircraftNonAtc; + } + + const QString &CSimConnectObject::typeToString(CSimConnectObject::SimObjectType type) + { + static const QString a1("aircraft (non ATC)"); + static const QString a2("aircraft (sim.object)"); + static const QString p("probe"); + static const QString u("unknown"); + switch (type) + { + case AircraftNonAtc: return a1; + case AircraftSimulatedObject: return a2; + case TerrainProbe: return p; + default: break; + } + return u; + } + + bool CSimConnectObject::isSameTypeGroup(CSimConnectObject::SimObjectType t1, CSimConnectObject::SimObjectType t2) + { + if (t1 == t2) { return true; } + return isAircraft(t1) && isAircraft(t2); + } + + bool CSimConnectObject::isAircraft(CSimConnectObject::SimObjectType type) + { + return CSimConnectObject::AircraftNonAtc == type || CSimConnectObject::AircraftSimulatedObject; + } + + bool CSimConnectObjects::insert(const CSimConnectObject &simObject, bool updateTimestamp) + { + if (!simObject.hasCallsign()) { return false; } + if (updateTimestamp) + { + CSimConnectObject simObj(simObject); + simObj.resetTimestampToNow(); + (*this)[simObj.getCallsign()] = simObj; + } + else { (*this)[simObject.getCallsign()] = simObject; } + return true; + } + + bool CSimConnectObjects::setSimConnectObjectIdForRequestId(DWORD requestId, DWORD objectId) + { + // First check, if this request id belongs to us + auto it = std::find_if(this->begin(), this->end(), + [requestId](const CSimConnectObject &obj) { return obj.getRequestId() == requestId; }); + if (it == this->end()) { return false; } + + // belongs to us + it->setObjectId(objectId); + return true; + } + + CCallsign CSimConnectObjects::getCallsignForObjectId(DWORD objectId) const + { + return this->getSimObjectForObjectId(objectId).getCallsign(); + } + + CCallsignSet CSimConnectObjects::getAllCallsigns(bool withoutProbes) const + { + if (this->isEmpty()) { return CCallsignSet(); } + if (!withoutProbes) { return CCallsignSet(this->keys()); } + CCallsignSet callsigns; + for (const CSimConnectObject &simObject : *this) + { + if (simObject.isAircraft()) { callsigns.insert(simObject.getCallsign().asString()); } + } + return callsigns; + } + + QStringList CSimConnectObjects::getAllCallsignStrings(bool sorted, bool withoutProbes) const + { + return this->getAllCallsigns(withoutProbes).getCallsignStrings(sorted); + } + + QString CSimConnectObjects::getAllCallsignStringsAsString(bool sorted, const QString &separator) const + { + return this->getAllCallsignStrings(sorted).join(separator); + } + + CSimConnectObject CSimConnectObjects::getSimObjectForObjectId(DWORD objectId) const + { + for (const CSimConnectObject &simObject : *this) + { + if (simObject.getObjectId() == objectId) { return simObject; } + } + return CSimConnectObject(); + } + + CSimConnectObject CSimConnectObjects::getOldestObject() const + { + if (this->isEmpty()) { return CSimConnectObject(); } + CSimConnectObject oldestSimObj = *this->begin(); + for (const CSimConnectObject &simObj : *this) + { + if (!simObj.hasCreatedTimestamp()) { continue; } + if (!oldestSimObj.hasCreatedTimestamp() || + oldestSimObj.getCreatedTimestamp() > simObj.getCreatedTimestamp()) + { + oldestSimObj = simObj; + } + } + return oldestSimObj; + } + + CSimConnectObject CSimConnectObjects::getSimObjectForRequestId(DWORD requestId) const + { + for (const CSimConnectObject &simObject : *this) + { + if (simObject.getRequestId() == requestId) { return simObject; } + } + return CSimConnectObject(); + } + + CSimConnectObject CSimConnectObjects::getSimObjectForOtherSimObject(const CSimConnectObject &otherSimObj) const + { + if (otherSimObj.hasValidObjectId()) + { + CSimConnectObject obj = this->getSimObjectForObjectId(otherSimObj.getObjectId()); + if (!obj.isInvalid()) { return obj; } + } + if (!otherSimObj.hasValidRequestId()) { return CSimConnectObject(); } + return this->getSimObjectForRequestId(otherSimObj.getRequestId()); + } + + bool CSimConnectObjects::isKnownSimObjectId(DWORD objectId) const + { + const CSimConnectObject simObject(this->getSimObjectForObjectId(objectId)); + return simObject.hasValidRequestAndObjectId() && objectId == simObject.getObjectId(); + } + + bool CSimConnectObjects::removeByObjectId(DWORD objectId) + { + const CSimConnectObject simObject(this->getSimObjectForObjectId(objectId)); + const int c = this->remove(simObject.getCallsign()); + return c > 0; + } + + bool CSimConnectObjects::removeByOtherSimObject(const CSimConnectObject &otherSimObj) + { + const int c = this->remove(otherSimObj.getCallsign()); + return c > 0; + } + + int CSimConnectObjects::removeAllProbes() + { + const QList probes = this->getProbes(); + int c = 0; + for (const CSimConnectObject &probe : probes) + { + this->remove(probe.getCallsign()); + c++; + } + return c; + } + + bool CSimConnectObjects::containsPendingAdded() const + { + for (const CSimConnectObject &simObject : *this) + { + if (simObject.isPendingAdded()) { return true; } + } + return false; + } + + bool CSimConnectObjects::containsPendingRemoved() const + { + for (const CSimConnectObject &simObject : *this) + { + if (simObject.isPendingRemoved()) { return true; } + } + return false; + } + + int CSimConnectObjects::countPendingAdded() const + { + int c = 0; + for (const CSimConnectObject &simObject : *this) + { + if (simObject.isPendingAdded()) { c++; } + } + return c; + } + + int CSimConnectObjects::countPendingRemoved() const + { + int c = 0; + for (const CSimConnectObject &simObject : *this) + { + if (simObject.isPendingRemoved()) { c++; } + } + return c; + } + + int CSimConnectObjects::countConfirmedAdded() + { + int c = 0; + for (const CSimConnectObject &simObject : std::as_const(*this)) + { + if (simObject.isConfirmedAdded()) { c++; } + } + return c; + } + + CCallsignSet CSimConnectObjects::getPendingAddedCallsigns() const + { + CCallsignSet callsigns; + for (const CSimConnectObject &simObject : *this) + { + if (simObject.isPendingAdded()) { callsigns.push_back(simObject.getCallsign()); } + } + return callsigns; + } + + CCallsignSet CSimConnectObjects::getPendingRemovedCallsigns() const + { + CCallsignSet callsigns; + for (const CSimConnectObject &simObject : *this) + { + if (simObject.isPendingRemoved()) { callsigns.push_back(simObject.getCallsign()); } + } + return callsigns; + } + + QList CSimConnectObjects::getByType(CSimConnectObject::SimObjectType type) const + { + QList objs; + for (const CSimConnectObject &simObject : *this) + { + if (simObject.getType() == type) { objs.push_back(simObject); } + } + return objs; + } + + QList CSimConnectObjects::getAircraft() const + { + QList l = this->getByType(CSimConnectObject::AircraftNonAtc); + l.append(this->getByType(CSimConnectObject::AircraftSimulatedObject)); + return l; + } + + CSimConnectObject CSimConnectObjects::getNotPendingProbe() const + { + for (const CSimConnectObject &simObject : *this) + { + if (simObject.getType() == CSimConnectObject::TerrainProbe && !simObject.isPending()) { return simObject; } + } + return CSimConnectObject(); + } + + CSimConnectObject CSimConnectObjects::getOldestNotPendingProbe() const + { + CSimConnectObject oldestProbe; + for (const CSimConnectObject &simObject : *this) + { + if (simObject.getType() == CSimConnectObject::TerrainProbe && !simObject.isPending()) + { + if (!oldestProbe.hasCreatedTimestamp() || + oldestProbe.getCreatedTimestamp() > simObject.getCreatedTimestamp()) + { + oldestProbe = simObject; + } + } + } + return oldestProbe; + } + + bool CSimConnectObjects::containsType(CSimConnectObject::SimObjectType type) const + { + for (const CSimConnectObject &simObject : *this) + { + if (simObject.getType() == type) { return true; } + } + return false; + } + + bool CSimConnectObjects::containsAircraft() const + { + return this->containsType(CSimConnectObject::AircraftNonAtc) || + this->containsType(CSimConnectObject::AircraftSimulatedObject); + } + + int CSimConnectObjects::removeCallsigns(const CCallsignSet &callsigns) + { + int c = 0; + for (const CCallsign &cs : callsigns) { c += this->remove(cs); } + return c; + } + + CSimConnectObjects CSimConnectObjects::removeOutdatedPendingAdded(CSimConnectObject::SimObjectType type) + { + CCallsignSet removeCallsigns; + CSimConnectObjects removedObjects; + + const qint64 ts = QDateTime::currentMSecsSinceEpoch(); + for (const CSimConnectObject &simObject : std::as_const(*this)) + { + // verification takes at least a second, so we need some time before outdating + if (type != CSimConnectObject::AllTypes && simObject.getType() != type) { continue; } + if (!simObject.isOutdatedPendingAdded(5000, ts)) { continue; } + removedObjects.insert(simObject); + removeCallsigns.insert(simObject.getCallsign()); + } + if (!removeCallsigns.isEmpty()) { this->removeCallsigns(removeCallsigns); } + return removedObjects; + } +} // namespace swift::simplugin::msfs2024common diff --git a/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.h b/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.h new file mode 100644 index 0000000000..6843c57e77 --- /dev/null +++ b/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.h @@ -0,0 +1,450 @@ +// 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_SIMCONNECTOBJECT_H +#define SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMCONNECTOBJECT_H + +#include +#include +#include + +#include "misc/simulation/interpolation/interpolatormulti.h" +#include "misc/simulation/simulatedaircraft.h" +#include "plugins/simulator/msfs2024/msfs2024export.h" +#include "plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h" +#include "plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.h" + +namespace swift::simplugin::msfs2024common +{ + //! Class representing a SimConnect object + class MSFS2024_EXPORT CSimConnectObject + { + public: + //! Type + enum SimObjectType + { + AircraftNonAtc, + AircraftSimulatedObject, + TerrainProbe, + AllTypes + }; + + //! Constructor + CSimConnectObject(); + + //! Constructor + CSimConnectObject(SimObjectType type); + + //! Constructor providing initial situation/parts + CSimConnectObject(const swift::misc::simulation::CSimulatedAircraft &aircraft, DWORD requestId, + swift::misc::simulation::ISimulationEnvironmentProvider *simEnvProvider, + swift::misc::simulation::IInterpolationSetupProvider *setupProvider, + swift::misc::simulation::IRemoteAircraftProvider *remoteAircraftProvider, + swift::misc::simulation::CInterpolationLogger *logger); + + //! Get callsign + const swift::misc::aviation::CCallsign &getCallsign() const { return m_aircraft.getCallsign(); } + + //! Get callsign + const QString &getCallsignAsString() const { return m_aircraft.getCallsign().asString(); } + + //! Callsign? + bool hasCallsign() const { return !this->getCallsign().isEmpty(); } + + //! Simulated aircraft (as added) + const swift::misc::simulation::CSimulatedAircraft &getAircraft() const { return m_aircraft; } + + //! Simulated aircraft model + const swift::misc::simulation::CAircraftModel &getAircraftModel() const { return m_aircraft.getModel(); } + + //! Simulated aircraft model string + const QString &getAircraftModelString() const { return m_aircraft.getModelString(); } + + //! Object type + SimObjectType getType() const { return m_type; } + + //! Type as string + const QString &getTypeAsString() const { return typeToString(m_type); } + + //! Aircraft? + bool isAircraft() const + { + return this->getType() == AircraftNonAtc || this->getType() == AircraftSimulatedObject; + } + + //! Aircraft simulated object? + bool isAircraftSimulatedObject() const { return this->getType() == AircraftSimulatedObject; } + + //! Aircraft NON ATC? + bool isAircraftNonAtc() const { return this->getType() == AircraftNonAtc; } + + //! Probe? + bool isTerrainProbe() const { return this->getType() == TerrainProbe; } + + //! Set the type + void setType(SimObjectType type) { m_type = type; } + + //! Set the aircraft + void setAircraft(const swift::misc::simulation::CSimulatedAircraft &aircraft); + + //! Set model string + void setAircraftModelString(const QString &modelString); + + //! Set CG + void setAircraftCG(const swift::misc::physical_quantities::CLength &cg); + + //! Get current lights (requested from simulator) + const swift::misc::aviation::CAircraftLights &getCurrentLightsInSimulator() const + { + return m_currentLightsInSim; + } + + //! Received lights in simulator + bool hasCurrentLightsInSimulator() const { return !m_currentLightsInSim.isNull(); } + + //! Set current lights when received from simulator + void setCurrentLightsInSimulator(const swift::misc::aviation::CAircraftLights &lights) + { + m_currentLightsInSim = lights; + } + + //! Pretend to have received lights from simulator + void fakeCurrentLightsInSimulator() { m_currentLightsInSim.setNull(false); } + + //! Lights as sent to simulator + const swift::misc::aviation::CAircraftLights &getLightsAsSent() const { return m_lightsAsSent; } + + //! Lights as sent to simulator + void setLightsAsSent(const swift::misc::aviation::CAircraftLights &lights) { m_lightsAsSent = lights; } + + //! How often do we request data from simulator for this remote aircraft + SIMCONNECT_PERIOD getSimDataPeriod() const { return m_requestSimDataPeriod; } + + //! How often do we request data from simulator for this remote aircraft + void setSimDataPeriod(SIMCONNECT_PERIOD period) { m_requestSimDataPeriod = period; } + + //! Set Simconnect request id + void setRequestId(DWORD id); + + //! Get SimConnect request id + DWORD getRequestId() const { return m_requestId; } + + //! Get SimConnect with offset + DWORD getRequestId(CSimConnectDefinitions::SimObjectRequest offset) const; + + //! Set Simconnect object id + void setObjectId(DWORD id); + + //! Get SimConnect object id + DWORD getObjectId() const { return m_objectId; } + + //! Get SimConnect object id + QString getObjectIdAsString() const { return QString::number(this->getObjectId()); } + + //! Valid request id? + bool hasValidRequestId() const { return m_validRequestId; } + + //! Valid object id? + bool hasValidObjectId() const { return m_validObjectId; } + + //! Object is requested in simulator, not yet confirmed added + bool isPendingAdded() const; + + //! Still pending + bool isOutdatedPendingAdded(qint64 thresholdMs = 5000, qint64 currentMsSinceEpoch = -1) const; + + //! Adding is confirmed + bool isConfirmedAdded() const; + + //! Marked as confirmed, means the simulator has "confirmed" the objectId as added and not instantly removed the + //! object + void setConfirmedAdded(bool confirm); + + //! @{ + //! Special states + bool isAddedWhileRemoving() { return m_addedWhileRemoving; } + void setAddedWhileRemoving(bool addedWileRemoved); + bool isRemovedWhileAdding() const { return m_removedWhileAdding; } + void setRemovedWhileAdding(bool removedWhileAdding); + //! @} + + //! Removing is pending + bool isPendingRemoved() const { return m_pendingRemoved; } + + //! Object which can be used for sending, not pending and valid ids + bool isReadyToSend() const; + + //! Marked as pending for removal + void setPendingRemoved(bool pending); + + //! Pending added or removed? + bool isPending() const { return this->isPendingAdded() || this->isPendingRemoved(); } + + //! Has camera? + bool hasCamera() const { return m_camera; } + + //! Reset camera positions + void resetCameraPositions(); + + //! Camera position + const SIMCONNECT_DATA_XYZ &cameraPosition() const { return m_cameraPosition; } + + //! Camera rotation; + const SIMCONNECT_DATA_PBH &cameraRotation() const { return m_cameraRotation; } + + //! Camera position/rotation + void setCameraPositionAndRotation(const SIMCONNECT_DATA_XYZ &position, const SIMCONNECT_DATA_PBH &rotation) + { + m_cameraPosition = position; + m_cameraRotation = rotation; + } + + //! Camera GUID + GUID getCameraGUID() const { return m_cameraGuid; } + + //! Set camera GUID + void setCameraGUID(GUID guid) + { + m_cameraGuid = guid; + m_camera = true; + } + + //! No camera anymore + void removeCamera() { m_camera = false; } + + //! Set observer + void setObserverName(const QString &observer) { m_observerName = observer; } + + //! Observer name + const QString &getObserverName() const { return m_observerName; } + + //! Reset the state (like it was a new onject) without affecting interpolator and aircraft + void resetState(); + + //! Reset so it can be added again + void resetToAddAgain(); + + //! Reset the timestamp + void resetTimestampToNow() { m_tsCreated = QDateTime::currentMSecsSinceEpoch(); } + + //! VTOL? + bool isVtol() const { return m_aircraft.isVtol(); } + + //! Valid? + bool isValid() const { return !this->isInvalid(); } + + //! Invalid? + bool isInvalid() const { return !this->hasValidObjectId() && !this->hasValidRequestId(); } + + //! Created timestamp? + bool hasCreatedTimestamp() const { return m_tsCreated >= 0; } + + //! Created timestamp + qint64 getCreatedTimestamp() const { return m_tsCreated; } + + //! Engine count + int getEngineCount() const { return m_aircraft.getEnginesCount(); } + + //! Was the object really added to simulator + bool hasValidRequestAndObjectId() const; + + //! Adding has been failed before + int getAddingExceptions() const { return m_addingExceptions; } + + //! Set adding failed before + void setAddingExceptions(int number) { m_addingExceptions = number; } + + //! Increase adding exception + void increaseAddingExceptions() { m_addingExceptions++; } + + //! Decrease adding exception + void decreaseAddingExceptions() + { + if (m_addingExceptions > 0) { m_addingExceptions--; } + } + + //! Adding and directly removed + int getAddingDirectlyRemoved() const { return m_addingDirectlyRemoved; } + + //! Set adding and directly removed + void setAddingDirectlyRemoved(int number) { m_addingDirectlyRemoved = number; } + + //! Increase adding and directly removed + void increaseAddingDirectlyRemoved() { m_addingDirectlyRemoved++; } + + //! Copy the counters from another object + void copyAddingFailureCounters(const CSimConnectObject &otherObject); + + //! Callsign as LATIN1 + const QByteArray &getCallsignByteArray() const { return m_callsignByteArray; } + + //! \copydoc swift::misc::simulation::CInterpolator::getInterpolatorInfo + QString + getInterpolatorInfo(swift::misc::simulation::CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const; + + //! \copydoc swift::misc::simulation::CInterpolator::attachLogger + void attachInterpolatorLogger(swift::misc::simulation::CInterpolationLogger *logger) const; + + //! \copydoc swift::misc::simulation::CInterpolator::getInterpolation + swift::misc::simulation::CInterpolationResult + getInterpolation(qint64 currentTimeSinceEpoch, + const swift::misc::simulation::CInterpolationAndRenderingSetupPerCallsign &setup, + uint32_t aircraftNumber) const; + + //! \copydoc swift::misc::simulation::CInterpolator::getLastInterpolatedSituation + const swift::misc::aviation::CAircraftSituation &getLastInterpolatedSituation( + swift::misc::simulation::CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const; + + //! \copydoc swift::misc::simulation::CInterpolator::getInterpolationMessages + const swift::misc::CStatusMessageList &getInterpolationMessages( + swift::misc::simulation::CInterpolationAndRenderingSetupBase::InterpolatorMode mode) const; + + //! Interpolator + swift::misc::simulation::CInterpolatorMulti *getInterpolator() const { return m_interpolator.data(); } + + //! SimObject as string + QString toQString() const; + + //! Type of id + static SimObjectType requestIdToType(DWORD requestId); + + //! Type to string + static const QString &typeToString(SimObjectType type); + + //! Same type + static bool isSameTypeGroup(SimObjectType t1, SimObjectType t2); + + //! Aircraft? + static bool isAircraft(SimObjectType type); + + private: + swift::misc::simulation::CSimulatedAircraft m_aircraft; //!< corresponding aircraft + SimObjectType m_type = AircraftNonAtc; + DWORD m_requestId = 0; + DWORD m_objectId = 0; + bool m_validRequestId = false; + bool m_validObjectId = false; + bool m_confirmedAdded = false; + bool m_pendingRemoved = false; + bool m_camera = false; + bool m_removedWhileAdding = false; + bool m_addedWhileRemoving = false; + int m_addingExceptions = 0; //!< exception when added + int m_addingDirectlyRemoved = 0; //!< added, but removed directly afterwards + qint64 m_tsCreated = -1; + GUID m_cameraGuid; + SIMCONNECT_DATA_XYZ m_cameraPosition; + SIMCONNECT_DATA_PBH m_cameraRotation; + QByteArray m_callsignByteArray; + QString m_observerName; + swift::misc::aviation::CAircraftLights m_currentLightsInSim { + nullptr + }; //!< current lights to know state for toggling + swift::misc::aviation::CAircraftLights m_lightsAsSent { nullptr }; //!< lights as sent to simulator + SIMCONNECT_PERIOD m_requestSimDataPeriod = SIMCONNECT_PERIOD_NEVER; //!< how often do we query ground elevation + QSharedPointer + m_interpolator; //!< shared pointer because CSimConnectObject can be copied + }; + + //! Simulator objects (aka AI aircraft) + class CSimConnectObjects : public QHash + { + public: + //! Insert + bool insert(const CSimConnectObject &simObject, bool updateTimestamp = false); + + //! Set ID of a SimConnect object, so far we only have an request id in the object + bool setSimConnectObjectIdForRequestId(DWORD requestId, DWORD objectId); + + //! Find which callsign belongs to the object id + swift::misc::aviation::CCallsign getCallsignForObjectId(DWORD objectId) const; + + //! Get object per object id + CSimConnectObject getSimObjectForObjectId(DWORD objectId) const; + + //! Get object per request id + CSimConnectObject getSimObjectForRequestId(DWORD requestId) const; + + //! Get by request or object id, just as possible + CSimConnectObject getSimObjectForOtherSimObject(const CSimConnectObject &otherSimObj) const; + + //! Get the oldest object + CSimConnectObject getOldestObject() const; + + //! Is the object id one of our AI objects? + bool isKnownSimObjectId(DWORD objectId) const; + + //! Remove by id + bool removeByObjectId(DWORD objectId); + + //! Remove by object id or request id + bool removeByOtherSimObject(const CSimConnectObject &otherSimObj); + + //! Remove all the probes + int removeAllProbes(); + + //! Remove callsigns + int removeCallsigns(const swift::misc::aviation::CCallsignSet &callsigns); + + //! Remove all pending added objects + CSimConnectObjects removeOutdatedPendingAdded(CSimConnectObject::SimObjectType type); + + //! Pending add condition + bool containsPendingAdded() const; + + //! Pending removed condition + bool containsPendingRemoved() const; + + //! Number of pending added + int countPendingAdded() const; + + //! Number of pending removed + int countPendingRemoved() const; + + //! Objects not pending + int countConfirmedAdded(); + + //! Get all callsigns + swift::misc::aviation::CCallsignSet getAllCallsigns(bool withoutProbes = true) const; + + //! Get all callsign strings + QStringList getAllCallsignStrings(bool sorted = false, bool withoutProbes = true) const; + + //! Get all callsign strings as string + QString getAllCallsignStringsAsString(bool sorted = false, const QString &separator = ", ") const; + + //! Callsigns of pending added callsigns + swift::misc::aviation::CCallsignSet getPendingAddedCallsigns() const; + + //! Callsigns of pending removed callsigns + swift::misc::aviation::CCallsignSet getPendingRemovedCallsigns() const; + + //! Get by type + QList getByType(CSimConnectObject::SimObjectType type) const; + + //! All probes + QList getProbes() const { return this->getByType(CSimConnectObject::TerrainProbe); } + + //! All aircraft + QList getAircraft() const; + + //! Get a non pending probe + CSimConnectObject getNotPendingProbe() const; + + //! Get a non pending probe + CSimConnectObject getOldestNotPendingProbe() const; + + //! Contains object of type + bool containsType(CSimConnectObject::SimObjectType type) const; + + //! Probe? + bool containsProbe() const { return this->containsType(CSimConnectObject::TerrainProbe); } + + //! Aircraft? + bool containsAircraft() const; + }; +} // namespace swift::simplugin::msfs2024common + +#endif // SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMCONNECTOBJECT_H diff --git a/src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.cpp b/src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.cpp new file mode 100644 index 0000000000..0396cebdb8 --- /dev/null +++ b/src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.cpp @@ -0,0 +1,585 @@ +// SPDX-FileCopyrightText: Copyright (C) 2018 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +#include "simconnectsymbolsmsfs2024.h" + +// clang-format off +#include +//#include +#include "../third_party/externals/common/include/simconnect/MSFS2024/SimConnect.h" +// clang-format on + +#include + +#include + +#include "misc/logcategories.h" +#include "misc/logmessage.h" +#include "misc/stringutils.h" + +// clazy:excludeall=function-args-by-ref + +using namespace swift::misc; + +bool loadAndResolveSimConnect(bool manifestProbing) +{ + Q_UNUSED(manifestProbing); + return true; +} + +// MSFS2024 API: +// https://docs.flightsimulator.com/msfs2024/html/6_Programming_APIs/SimConnect/SimConnect_API_Reference.htm +using PfnSimConnect_Open = HRESULT(__stdcall *)(HANDLE *, LPCSTR, HWND, DWORD, HANDLE, DWORD); +using PfnSimConnect_Close = HRESULT(__stdcall *)(HANDLE); +using PfnSimConnect_AddToDataDefinition = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_DATA_DEFINITION_ID, const char *, + const char *, SIMCONNECT_DATATYPE, float, DWORD); +using PfnSimConnect_Text = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_TEXT_TYPE, float, SIMCONNECT_CLIENT_EVENT_ID, DWORD, + void *); +using PfnSimConnect_CallDispatch = HRESULT(__stdcall *)(HANDLE, DispatchProc, void *); +using PfnSimConnect_WeatherSetModeCustom = HRESULT(__stdcall *)(HANDLE); +using PfnSimConnect_WeatherSetModeGlobal = HRESULT(__stdcall *)(HANDLE); +using PfnSimConnect_WeatherSetObservation = HRESULT(__stdcall *)(HANDLE, DWORD, const char *); +using PfnSimConnect_TransmitClientEvent = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_OBJECT_ID, SIMCONNECT_CLIENT_EVENT_ID, + DWORD, SIMCONNECT_NOTIFICATION_GROUP_ID, + SIMCONNECT_EVENT_FLAG); +using PfnSimConnect_SetClientData = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_CLIENT_DATA_ID, + SIMCONNECT_CLIENT_DATA_DEFINITION_ID, + SIMCONNECT_CLIENT_DATA_SET_FLAG, DWORD, DWORD, void *); +using PfnSimConnect_RequestDataOnSimObject = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_DATA_REQUEST_ID, + SIMCONNECT_DATA_DEFINITION_ID, SIMCONNECT_OBJECT_ID, + SIMCONNECT_PERIOD, SIMCONNECT_DATA_REQUEST_FLAG, + DWORD, DWORD, DWORD); +using PfnSimConnect_RequestDataOnSimObjectType = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_DATA_REQUEST_ID, + SIMCONNECT_DATA_DEFINITION_ID, DWORD, + SIMCONNECT_SIMOBJECT_TYPE); +using PfnSimConnect_RequestClientData = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_CLIENT_DATA_ID, + SIMCONNECT_DATA_REQUEST_ID, + SIMCONNECT_CLIENT_DATA_DEFINITION_ID, + SIMCONNECT_CLIENT_DATA_PERIOD, + SIMCONNECT_CLIENT_DATA_REQUEST_FLAG, DWORD, DWORD, DWORD); +using PfnSimConnect_SubscribeToSystemEvent = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_CLIENT_EVENT_ID, const char *); +using PfnSimConnect_MapClientEventToSimEvent = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_CLIENT_EVENT_ID, const char *); +using PfnSimConnect_SubscribeToFacilities = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_FACILITY_LIST_TYPE, + SIMCONNECT_DATA_REQUEST_ID); +using PfnSimConnect_GetLastSentPacketID = HRESULT(__stdcall *)(HANDLE, DWORD *); +using PfnSimConnect_AIRemoveObject = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_OBJECT_ID, SIMCONNECT_DATA_REQUEST_ID); +using PfnSimConnect_SetDataOnSimObject = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_DATA_DEFINITION_ID, + SIMCONNECT_OBJECT_ID, SIMCONNECT_DATA_SET_FLAG, DWORD, + DWORD, void *); +using PfnSimConnect_AIReleaseControl = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_OBJECT_ID, SIMCONNECT_DATA_REQUEST_ID); +using PfnSimConnect_AICreateNonATCAircraft = HRESULT(__stdcall *)(HANDLE, const char *, const char *, + SIMCONNECT_DATA_INITPOSITION, + SIMCONNECT_DATA_REQUEST_ID); +using PfnSimConnect_AICreateNonATCAircraft_EX1 = HRESULT(__stdcall *)(HANDLE, const char *, const char *, const char *, + SIMCONNECT_DATA_INITPOSITION, + SIMCONNECT_DATA_REQUEST_ID); + +using PfnSimConnect_AICreateEnrouteATCAircraft = HRESULT(__stdcall *)(HANDLE, const char *, const char *, int, + const char *, double, BOOL, + SIMCONNECT_DATA_REQUEST_ID); +using PfnSimConnect_AICreateParkedATCAircraft = HRESULT(__stdcall *)(HANDLE, const char *, const char *, const char *, + SIMCONNECT_DATA_REQUEST_ID); +using PfnSimConnect_AICreateSimulatedObject = HRESULT(__stdcall *)(HANDLE, const char *, SIMCONNECT_DATA_INITPOSITION, + SIMCONNECT_DATA_REQUEST_ID); + +using PfnSimConnect_MapClientDataNameToID = HRESULT(__stdcall *)(HANDLE, const char *, SIMCONNECT_CLIENT_DATA_ID); +using PfnSimConnect_CreateClientData = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_CLIENT_DATA_ID, DWORD, + SIMCONNECT_CREATE_CLIENT_DATA_FLAG); +using PfnSimConnect_AddToClientDataDefinition = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_CLIENT_DATA_DEFINITION_ID, + DWORD, DWORD, float, DWORD); + +#ifdef Q_OS_WIN64 +// using PfnSimConnect_RequestGroundInfo = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_DATA_REQUEST_ID, double, double, +// double, +// double, double, double, DWORD, DWORD, +// SIMCONNECT_GROUND_INFO_LATLON_FORMAT, +// SIMCONNECT_GROUND_INFO_ALT_FORMAT, +// SIMCONNECT_GROUND_INFO_SOURCE_FLAG); +using PfnSimConnect_ChangeView = HRESULT(__stdcall *)(HANDLE, const char *); +using PfnSimConnect_AIReleaseControlEx = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_OBJECT_ID, SIMCONNECT_DATA_REQUEST_ID, + BOOL); +using PfnSimConnect_CloseView = HRESULT(__stdcall *)(HANDLE, const char *); +using PfnSimConnect_OpenView = HRESULT(__stdcall *)(HANDLE, const char *, const char *); +using PfnSimConnect_ChangeView = HRESULT(__stdcall *)(HANDLE, const char *); +using PfnSimConnect_CreateCameraInstance = HRESULT(__stdcall *)(HANDLE, const GUID, const char *, SIMCONNECT_OBJECT_ID, + SIMCONNECT_DATA_REQUEST_ID); +using PfnSimConnect_DeleteCameraInstance = HRESULT(__stdcall *)(HANDLE, const GUID, UINT32); +// using PfnSimConnect_CreateCameraDefinition = HRESULT(__stdcall *)(HANDLE, const GUID, SIMCONNECT_CAMERA_TYPE, +// const char *, SIMCONNECT_DATA_XYZ, +// SIMCONNECT_DATA_PBH); +using PfnSimConnect_ObserverAttachToEntityOn = HRESULT(__stdcall *)(HANDLE, const char *, DWORD, SIMCONNECT_DATA_XYZ); +// using PfnSimConnect_CreateObserver = HRESULT(__stdcall *)(HANDLE, const char *, SIMCONNECT_DATA_OBSERVER); +using PfnSimConnect_SetObserverLookAt = HRESULT(__stdcall *)(HANDLE, const char *, SIMCONNECT_DATA_LATLONALT); +using PfnSimConnect_SimConnect_EnumerateSimObjectsAndLiveries = HRESULT(__stdcall *)(HANDLE, SIMCONNECT_DATA_REQUEST_ID, + SIMCONNECT_SIMOBJECT_TYPE); +using PfnSimConnect_AICreateSimulatedObject_EX1 = HRESULT(__stdcall *)(HANDLE, const char *, const char *, + SIMCONNECT_DATA_INITPOSITION, + SIMCONNECT_DATA_REQUEST_ID); + +#endif + +//! The SimConnect Symbols +//! \private +struct SimConnectSymbols +{ + PfnSimConnect_Open SimConnect_Open = nullptr; + PfnSimConnect_Close SimConnect_Close = nullptr; + PfnSimConnect_AddToDataDefinition SimConnect_AddToDataDefinition = nullptr; + PfnSimConnect_Text SimConnect_Text = nullptr; + PfnSimConnect_CallDispatch SimConnect_CallDispatch = nullptr; + PfnSimConnect_WeatherSetModeCustom SimConnect_WeatherSetModeCustom = nullptr; + PfnSimConnect_WeatherSetModeGlobal SimConnect_WeatherSetModeGlobal = nullptr; + PfnSimConnect_WeatherSetObservation SimConnect_WeatherSetObservation = nullptr; + PfnSimConnect_TransmitClientEvent SimConnect_TransmitClientEvent = nullptr; + PfnSimConnect_SetClientData SimConnect_SetClientData = nullptr; + PfnSimConnect_RequestDataOnSimObject SimConnect_RequestDataOnSimObject = nullptr; + PfnSimConnect_RequestDataOnSimObjectType SimConnect_RequestDataOnSimObjectType = nullptr; + PfnSimConnect_RequestClientData SimConnect_RequestClientData = nullptr; + PfnSimConnect_SubscribeToSystemEvent SimConnect_SubscribeToSystemEvent = nullptr; + PfnSimConnect_MapClientEventToSimEvent SimConnect_MapClientEventToSimEvent = nullptr; + PfnSimConnect_SubscribeToFacilities SimConnect_SubscribeToFacilities = nullptr; + PfnSimConnect_GetLastSentPacketID SimConnect_GetLastSentPacketID = nullptr; + PfnSimConnect_AIRemoveObject SimConnect_AIRemoveObject = nullptr; + PfnSimConnect_SetDataOnSimObject SimConnect_SetDataOnSimObject = nullptr; + PfnSimConnect_AIReleaseControl SimConnect_AIReleaseControl = nullptr; + PfnSimConnect_AICreateNonATCAircraft SimConnect_AICreateNonATCAircraft = nullptr; + + PfnSimConnect_AICreateParkedATCAircraft SimConnect_AICreateParkedATCAircraft = nullptr; + PfnSimConnect_AICreateEnrouteATCAircraft SimConnect_AICreateEnrouteATCAircraft = nullptr; + PfnSimConnect_AICreateSimulatedObject SimConnect_AICreateSimulatedObject = nullptr; + + PfnSimConnect_MapClientDataNameToID SimConnect_MapClientDataNameToID = nullptr; + PfnSimConnect_CreateClientData SimConnect_CreateClientData = nullptr; + PfnSimConnect_AddToClientDataDefinition SimConnect_AddToClientDataDefinition = nullptr; +#ifdef Q_OS_WIN64 + // PfnSimConnect_RequestGroundInfo SimConnect_RequestGroundInfo = nullptr; + PfnSimConnect_ChangeView SimConnect_ChangeView = nullptr; + PfnSimConnect_AIReleaseControlEx SimConnect_AIReleaseControlEx = nullptr; + // PfnSimConnect_CreateCameraDefinition SimConnect_CreateCameraDefinition = nullptr; + PfnSimConnect_ObserverAttachToEntityOn SimConnect_ObserverAttachToEntityOn = nullptr; + // PfnSimConnect_CreateObserver SimConnect_CreateObserver = nullptr; + PfnSimConnect_CreateCameraInstance SimConnect_CreateCameraInstance = nullptr; + PfnSimConnect_DeleteCameraInstance SimConnect_DeleteCameraInstance = nullptr; + PfnSimConnect_SetObserverLookAt SimConnect_SetObserverLookAt = nullptr; + PfnSimConnect_OpenView SimConnect_OpenView = nullptr; + PfnSimConnect_CloseView SimConnect_CloseView = nullptr; + PfnSimConnect_SimConnect_EnumerateSimObjectsAndLiveries SimConnect_EnumerateSimObjectsAndLiveries = nullptr; + PfnSimConnect_AICreateNonATCAircraft_EX1 SimConnect_AICreateNonATCAircraft_EX1 = nullptr; + PfnSimConnect_AICreateSimulatedObject_EX1 SimConnect_AICreateSimulatedObject_EX1 = nullptr; +#endif +}; + +static SimConnectSymbols gSymbols; + +template +bool resolveSimConnectSymbol(QLibrary &library, FuncPtr &funcPtr, const char *funcName) +{ + funcPtr = reinterpret_cast(library.resolve(funcName)); + if (!funcPtr) + { + CLogMessage(CLogCategories::driver()).error(u"Failed to resolve %1: %2") << funcName << library.errorString(); + return false; + } + return true; +} + +bool resolveMsfs2024SimConnectSymbols(QLibrary &simConnectDll) +{ + bool resolveSuccess = true; + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_Open, "SimConnect_Open"); + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_Close, "SimConnect_Close"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AddToDataDefinition, + "SimConnect_AddToDataDefinition"); + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_Text, "SimConnect_Text"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_CallDispatch, + "SimConnect_CallDispatch"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_WeatherSetModeCustom, + "SimConnect_WeatherSetModeCustom"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_WeatherSetModeGlobal, + "SimConnect_WeatherSetModeGlobal"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_WeatherSetObservation, + "SimConnect_WeatherSetObservation"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_TransmitClientEvent, + "SimConnect_TransmitClientEvent"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_SetClientData, + "SimConnect_SetClientData"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_RequestDataOnSimObject, + "SimConnect_RequestDataOnSimObject"); + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_RequestDataOnSimObjectType, + "SimConnect_RequestDataOnSimObjectType"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_RequestClientData, + "SimConnect_RequestClientData"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_SubscribeToSystemEvent, + "SimConnect_SubscribeToSystemEvent"); + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_MapClientEventToSimEvent, + "SimConnect_MapClientEventToSimEvent"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_SubscribeToFacilities, + "SimConnect_SubscribeToFacilities"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_GetLastSentPacketID, + "SimConnect_GetLastSentPacketID"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AIRemoveObject, + "SimConnect_AIRemoveObject"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_SetDataOnSimObject, + "SimConnect_SetDataOnSimObject"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AIReleaseControl, + "SimConnect_AIReleaseControl"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AICreateNonATCAircraft, + "SimConnect_AICreateNonATCAircraft"); + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AICreateNonATCAircraft_EX1, + "SimConnect_AICreateNonATCAircraft_EX1"); + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AICreateEnrouteATCAircraft, + "SimConnect_AICreateEnrouteATCAircraft"); + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AICreateParkedATCAircraft, + "SimConnect_AICreateParkedATCAircraft"); + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AICreateSimulatedObject, + "SimConnect_AICreateSimulatedObject"); + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AICreateSimulatedObject_EX1, + "SimConnect_AICreateSimulatedObject_EX1"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_MapClientDataNameToID, + "SimConnect_MapClientDataNameToID"); + resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_CreateClientData, + "SimConnect_CreateClientData"); + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AddToClientDataDefinition, + "SimConnect_AddToClientDataDefinition"); + + resolveSuccess = + resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_EnumerateSimObjectsAndLiveries, + "SimConnect_EnumerateSimObjectsAndLiveries"); + + return resolveSuccess; +} + +#ifdef Q_OS_WIN64 +// bool resolveP3DSimConnectSymbols(QLibrary &simConnectDll) +//{ +// bool resolveSuccess = true; +// resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_RequestGroundInfo, +// "SimConnect_RequestGroundInfo"); +// resolveSuccess = resolveSuccess & +// resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_ChangeView, "SimConnect_ChangeView"); +// resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_AIReleaseControlEx, +// "SimConnect_AIReleaseControlEx"); +// resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, +// gSymbols.SimConnect_CreateCameraDefinition, +// "SimConnect_CreateCameraDefinition"); +// resolveSuccess = +// resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_ObserverAttachToEntityOn, +// "SimConnect_ObserverAttachToEntityOn"); +// resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_CreateObserver, +// "SimConnect_CreateObserver"); +// resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, +// gSymbols.SimConnect_CreateCameraInstance, +// "SimConnect_CreateCameraInstance"); +// resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, +// gSymbols.SimConnect_DeleteCameraInstance, +// "SimConnect_DeleteCameraInstance"); +// resolveSuccess = resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_SetObserverLookAt, +// "SimConnect_SetObserverLookAt"); +// resolveSuccess = +// resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_OpenView, "SimConnect_OpenView"); +// resolveSuccess = +// resolveSuccess & resolveSimConnectSymbol(simConnectDll, gSymbols.SimConnect_CloseView, +// "SimConnect_CloseView"); +// return resolveSuccess; +// } + +bool loadAndResolveMSFS2024SimConnect() +{ + // Check if already loaded + if (gSymbols.SimConnect_Open) { return true; } + + QString simConnectFileName(QStringLiteral("SimConnect.MSFS2024")); + + QLibrary simConnectDll(simConnectFileName); + simConnectDll.setLoadHints(QLibrary::PreventUnloadHint); + if (simConnectDll.load()) + { + const bool resolvedCommon = resolveMsfs2024SimConnectSymbols(simConnectDll); + if (!resolvedCommon) + { + CLogMessage(CLogCategories::driver()).error(u"Failed to resolve common symbols from SimConnect.dll: '%1'") + << simConnectFileName; + return false; + } + + CLogMessage(CLogCategories::driver()).info(u"Loaded and resolved MSFS2024 symbols from SimConnect.dll: '%1'") + << simConnectFileName; + return resolvedCommon; + } + else + { + CLogMessage(CLogCategories::driver()).error(u"Failed to load SimConnect.dll: '%1' '%2'") + << simConnectFileName << simConnectDll.errorString(); + return false; + } +} + +#endif + +SIMCONNECTAPI SimConnect_Open(HANDLE *phSimConnect, LPCSTR szName, HWND hWnd, DWORD UserEventWin32, HANDLE hEventHandle, + DWORD ConfigIndex) +{ + return gSymbols.SimConnect_Open(phSimConnect, szName, hWnd, UserEventWin32, hEventHandle, ConfigIndex); +} + +SIMCONNECTAPI SimConnect_Close(HANDLE hSimConnect) { return gSymbols.SimConnect_Close(hSimConnect); } + +SIMCONNECTAPI SimConnect_AddToDataDefinition(HANDLE hSimConnect, SIMCONNECT_DATA_DEFINITION_ID DefineID, + const char *DatumName, const char *UnitsName, + SIMCONNECT_DATATYPE DatumType, float fEpsilon, DWORD DatumID) +{ + return gSymbols.SimConnect_AddToDataDefinition(hSimConnect, DefineID, DatumName, UnitsName, DatumType, fEpsilon, + DatumID); +} + +SIMCONNECTAPI SimConnect_EnumerateSimObjectsAndLiveries(HANDLE hSimConnect, SIMCONNECT_DATA_REQUEST_ID RequestID, + SIMCONNECT_SIMOBJECT_TYPE Type) +{ + return gSymbols.SimConnect_EnumerateSimObjectsAndLiveries(hSimConnect, RequestID, Type); +} + +SIMCONNECTAPI SimConnect_Text(HANDLE hSimConnect, SIMCONNECT_TEXT_TYPE type, float fTimeSeconds, + SIMCONNECT_CLIENT_EVENT_ID EventID, DWORD cbUnitSize, void *pDataSet) +{ + return gSymbols.SimConnect_Text(hSimConnect, type, fTimeSeconds, EventID, cbUnitSize, pDataSet); +} + +SIMCONNECTAPI SimConnect_CallDispatch(HANDLE hSimConnect, DispatchProc pfcnDispatch, void *pContext) +{ + return gSymbols.SimConnect_CallDispatch(hSimConnect, pfcnDispatch, pContext); +} + +SIMCONNECTAPI SimConnect_WeatherSetModeCustom(HANDLE hSimConnect) +{ + return gSymbols.SimConnect_WeatherSetModeCustom(hSimConnect); +} + +SIMCONNECTAPI SimConnect_WeatherSetModeGlobal(HANDLE hSimConnect) +{ + return gSymbols.SimConnect_WeatherSetModeGlobal(hSimConnect); +} + +SIMCONNECTAPI SimConnect_WeatherSetObservation(HANDLE hSimConnect, DWORD Seconds, const char *szMETAR) +{ + return gSymbols.SimConnect_WeatherSetObservation(hSimConnect, Seconds, szMETAR); +} + +SIMCONNECTAPI SimConnect_TransmitClientEvent(HANDLE hSimConnect, SIMCONNECT_OBJECT_ID ObjectID, + SIMCONNECT_CLIENT_EVENT_ID EventID, DWORD dwData, + SIMCONNECT_NOTIFICATION_GROUP_ID GroupID, SIMCONNECT_EVENT_FLAG Flags) +{ + return gSymbols.SimConnect_TransmitClientEvent(hSimConnect, ObjectID, EventID, dwData, GroupID, Flags); +} + +SIMCONNECTAPI SimConnect_SetClientData(HANDLE hSimConnect, SIMCONNECT_CLIENT_DATA_ID ClientDataID, + SIMCONNECT_CLIENT_DATA_DEFINITION_ID DefineID, + SIMCONNECT_CLIENT_DATA_SET_FLAG Flags, DWORD dwReserved, DWORD cbUnitSize, + void *pDataSet) +{ + return gSymbols.SimConnect_SetClientData(hSimConnect, ClientDataID, DefineID, Flags, dwReserved, cbUnitSize, + pDataSet); +} + +SIMCONNECTAPI SimConnect_RequestDataOnSimObject(HANDLE hSimConnect, SIMCONNECT_DATA_REQUEST_ID RequestID, + SIMCONNECT_DATA_DEFINITION_ID DefineID, SIMCONNECT_OBJECT_ID ObjectID, + SIMCONNECT_PERIOD Period, SIMCONNECT_DATA_REQUEST_FLAG Flags, + DWORD origin, DWORD interval, DWORD limit) +{ + return gSymbols.SimConnect_RequestDataOnSimObject(hSimConnect, RequestID, DefineID, ObjectID, Period, Flags, origin, + interval, limit); +} + +SIMCONNECTAPI SimConnect_RequestDataOnSimObjectType(HANDLE hSimConnect, SIMCONNECT_DATA_REQUEST_ID RequestID, + SIMCONNECT_DATA_DEFINITION_ID DefineID, DWORD dwRadiusMeters, + SIMCONNECT_SIMOBJECT_TYPE type) +{ + return gSymbols.SimConnect_RequestDataOnSimObjectType(hSimConnect, RequestID, DefineID, dwRadiusMeters, type); +} + +SIMCONNECTAPI SimConnect_RequestClientData(HANDLE hSimConnect, SIMCONNECT_CLIENT_DATA_ID ClientDataID, + SIMCONNECT_DATA_REQUEST_ID RequestID, + SIMCONNECT_CLIENT_DATA_DEFINITION_ID DefineID, + SIMCONNECT_CLIENT_DATA_PERIOD Period, + SIMCONNECT_CLIENT_DATA_REQUEST_FLAG Flags, DWORD origin, DWORD interval, + DWORD limit) +{ + return gSymbols.SimConnect_RequestClientData(hSimConnect, ClientDataID, RequestID, DefineID, Period, Flags, origin, + interval, limit); +} + +SIMCONNECTAPI SimConnect_SubscribeToSystemEvent(HANDLE hSimConnect, SIMCONNECT_CLIENT_EVENT_ID EventID, + const char *SystemEventName) +{ + return gSymbols.SimConnect_SubscribeToSystemEvent(hSimConnect, EventID, SystemEventName); +} + +SIMCONNECTAPI SimConnect_MapClientEventToSimEvent(HANDLE hSimConnect, SIMCONNECT_CLIENT_EVENT_ID EventID, + const char *EventName) +{ + return gSymbols.SimConnect_MapClientEventToSimEvent(hSimConnect, EventID, EventName); +} + +SIMCONNECTAPI SimConnect_SubscribeToFacilities(HANDLE hSimConnect, SIMCONNECT_FACILITY_LIST_TYPE type, + SIMCONNECT_DATA_REQUEST_ID RequestID) +{ + return gSymbols.SimConnect_SubscribeToFacilities(hSimConnect, type, RequestID); +} + +SIMCONNECTAPI SimConnect_GetLastSentPacketID(HANDLE hSimConnect, DWORD *pdwError) +{ + return gSymbols.SimConnect_GetLastSentPacketID(hSimConnect, pdwError); +} + +SIMCONNECTAPI SimConnect_AIRemoveObject(HANDLE hSimConnect, SIMCONNECT_OBJECT_ID ObjectID, + SIMCONNECT_DATA_REQUEST_ID RequestID) +{ + return gSymbols.SimConnect_AIRemoveObject(hSimConnect, ObjectID, RequestID); +} + +SIMCONNECTAPI SimConnect_SetDataOnSimObject(HANDLE hSimConnect, SIMCONNECT_DATA_DEFINITION_ID DefineID, + SIMCONNECT_OBJECT_ID ObjectID, SIMCONNECT_DATA_SET_FLAG Flags, + DWORD ArrayCount, DWORD cbUnitSize, void *pDataSet) +{ + return gSymbols.SimConnect_SetDataOnSimObject(hSimConnect, DefineID, ObjectID, Flags, ArrayCount, cbUnitSize, + pDataSet); +} + +SIMCONNECTAPI SimConnect_AIReleaseControl(HANDLE hSimConnect, SIMCONNECT_OBJECT_ID ObjectID, + SIMCONNECT_DATA_REQUEST_ID RequestID) +{ + return gSymbols.SimConnect_AIReleaseControl(hSimConnect, ObjectID, RequestID); +} + +SIMCONNECTAPI SimConnect_AICreateNonATCAircraft(HANDLE hSimConnect, const char *szContainerTitle, + const char *szTailNumber, SIMCONNECT_DATA_INITPOSITION InitPos, + SIMCONNECT_DATA_REQUEST_ID RequestID) +{ + return gSymbols.SimConnect_AICreateNonATCAircraft(hSimConnect, szContainerTitle, szTailNumber, InitPos, RequestID); +} + +SIMCONNECTAPI SimConnect_AICreateNonATCAircraft_EX1(HANDLE hSimConnect, const char *szContainerTitle, + const char *szContainerLivery, const char *szTailNumber, + SIMCONNECT_DATA_INITPOSITION InitPos, + SIMCONNECT_DATA_REQUEST_ID RequestID) +{ + return gSymbols.SimConnect_AICreateNonATCAircraft_EX1(hSimConnect, szContainerTitle, szContainerLivery, + szTailNumber, InitPos, RequestID); +} + +SIMCONNECTAPI SimConnect_AICreateEnrouteATCAircraft(HANDLE hSimConnect, const char *szContainerTitle, + const char *szTailNumber, int iFlightNumber, + const char *szFlightPlanPath, double dFlightPlanPosition, + BOOL bTouchAndGo, SIMCONNECT_DATA_REQUEST_ID RequestID) +{ + return gSymbols.SimConnect_AICreateEnrouteATCAircraft(hSimConnect, szContainerTitle, szTailNumber, iFlightNumber, + szFlightPlanPath, dFlightPlanPosition, bTouchAndGo, + RequestID); +} + +SIMCONNECTAPI SimConnect_AICreateParkedATCAircraft(HANDLE hSimConnect, const char *szContainerTitle, + const char *szTailNumber, const char *szAirportID, + SIMCONNECT_DATA_REQUEST_ID RequestID) +{ + return gSymbols.SimConnect_AICreateParkedATCAircraft(hSimConnect, szContainerTitle, szTailNumber, szAirportID, + RequestID); +} + +SIMCONNECTAPI SimConnect_AICreateSimulatedObject_EX1(HANDLE hSimConnect, const char *szContainerTitle, + const char *szContainerLivery, + SIMCONNECT_DATA_INITPOSITION InitPos, + SIMCONNECT_DATA_REQUEST_ID RequestID) +{ + return gSymbols.SimConnect_AICreateSimulatedObject_EX1(hSimConnect, szContainerTitle, szContainerLivery, InitPos, + RequestID); +} + +SIMCONNECTAPI SimConnect_AICreateSimulatedObject(HANDLE hSimConnect, const char *szContainerTitle, + SIMCONNECT_DATA_INITPOSITION InitPos, + SIMCONNECT_DATA_REQUEST_ID RequestID) +{ + return gSymbols.SimConnect_AICreateSimulatedObject(hSimConnect, szContainerTitle, InitPos, RequestID); +} + +SIMCONNECTAPI SimConnect_MapClientDataNameToID(HANDLE hSimConnect, const char *szClientDataName, + SIMCONNECT_CLIENT_DATA_ID ClientDataID) +{ + return gSymbols.SimConnect_MapClientDataNameToID(hSimConnect, szClientDataName, ClientDataID); +} + +SIMCONNECTAPI SimConnect_CreateClientData(HANDLE hSimConnect, SIMCONNECT_CLIENT_DATA_ID ClientDataID, DWORD dwSize, + SIMCONNECT_CREATE_CLIENT_DATA_FLAG Flags) +{ + return gSymbols.SimConnect_CreateClientData(hSimConnect, ClientDataID, dwSize, Flags); +} + +SIMCONNECTAPI SimConnect_AddToClientDataDefinition(HANDLE hSimConnect, SIMCONNECT_CLIENT_DATA_DEFINITION_ID DefineID, + DWORD dwOffset, DWORD dwSizeOrType, float fEpsilon, DWORD DatumID) +{ + return gSymbols.SimConnect_AddToClientDataDefinition(hSimConnect, DefineID, dwOffset, dwSizeOrType, fEpsilon, + DatumID); +} + +#ifdef Q_OS_WIN64 +// SIMCONNECTAPI SimConnect_RequestGroundInfo(HANDLE hSimConnect, SIMCONNECT_DATA_REQUEST_ID RequestID, double minLat, +// double minLon, double minAlt, double maxLat, double maxLon, double maxAlt, +// DWORD dwGridWidth, DWORD dwGridHeight, +// SIMCONNECT_GROUND_INFO_LATLON_FORMAT eLatLonFormat, +// SIMCONNECT_GROUND_INFO_ALT_FORMAT eAltFormat, +// SIMCONNECT_GROUND_INFO_SOURCE_FLAG eSourceFlags) +//{ +// return gSymbols.SimConnect_RequestGroundInfo(hSimConnect, RequestID, minLat, minLon, minAlt, maxLat, maxLon, +// maxAlt, +// dwGridWidth, dwGridHeight, eLatLonFormat, eAltFormat, eSourceFlags); +// } + +SIMCONNECTAPI SimConnect_ChangeView(HANDLE hSimConnect, const char *szName) +{ + return gSymbols.SimConnect_ChangeView(hSimConnect, szName); +} + +SIMCONNECTAPI SimConnect_AIReleaseControlEx(HANDLE hSimConnect, SIMCONNECT_OBJECT_ID ObjectID, + SIMCONNECT_DATA_REQUEST_ID RequestID, BOOL destroyAI) +{ + return gSymbols.SimConnect_AIReleaseControlEx(hSimConnect, ObjectID, RequestID, destroyAI); +} + +SIMCONNECTAPI SimConnect_ObserverAttachToEntityOn(HANDLE hSimConnect, const char *szName, DWORD dwObjectID, + SIMCONNECT_DATA_XYZ Offset) +{ + return gSymbols.SimConnect_ObserverAttachToEntityOn(hSimConnect, szName, dwObjectID, Offset); +} + +// SIMCONNECTAPI SimConnect_CreateObserver(HANDLE hSimConnect, const char *szName, SIMCONNECT_DATA_OBSERVER +// ObserverData) +//{ +// return gSymbols.SimConnect_CreateObserver(hSimConnect, szName, ObserverData); +// } + +SIMCONNECTAPI SimConnect_OpenView(HANDLE hSimConnect, const char *szName, const char *szTitle) +{ + return gSymbols.SimConnect_OpenView(hSimConnect, szName, szTitle); +} + +SIMCONNECTAPI SimConnect_CloseView(HANDLE hSimConnect, const char *szName) +{ + return gSymbols.SimConnect_CloseView(hSimConnect, szName); +} + +SIMCONNECTAPI SimConnect_SetObserverLookAt(HANDLE hSimConnect, const char *szName, + SIMCONNECT_DATA_LATLONALT TargetPosition) +{ + return gSymbols.SimConnect_SetObserverLookAt(hSimConnect, szName, TargetPosition); +} + +#endif diff --git a/src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.h b/src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.h new file mode 100644 index 0000000000..805701ff7b --- /dev/null +++ b/src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.h @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: Copyright (C) 2018 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +//! \file + +#ifndef SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMCONNECTSYMBOLS_H +#define SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMCONNECTSYMBOLS_H + +#include + +#include "plugins/simulator/msfs2024/msfs2024export.h" + +MSFS2024_EXPORT bool loadAndResolveMSFS2024SimConnect(); + +#endif // SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMCONNECTSYMBOLS_H diff --git a/src/plugins/simulator/msfs2024/simconnectwindowsmsfs2024.h b/src/plugins/simulator/msfs2024/simconnectwindowsmsfs2024.h new file mode 100644 index 0000000000..b5c84a94ca --- /dev/null +++ b/src/plugins/simulator/msfs2024/simconnectwindowsmsfs2024.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Copyright (C) 2018 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +// in P3Dv4 the simconnect.h does not include windows.h +// here we include windows.h first + +#ifndef SWIFT_SIMPLUGIN_MSFS2024_SIMCONNECTWINDOWS_H +#define SWIFT_SIMPLUGIN_MSFS2024_SIMCONNECTWINDOWS_H + +#ifndef NOMINMAX +# define NOMINMAX +#endif + +// clash with struct interface in objbase.h used to happen +#pragma push_macro("interface") +#undef interface + +// clang-format off +#include +//#include +#include "../third_party/externals/common/include/simconnect/MSFS2024/SimConnect.h" +// clang-format on + +#include + +#pragma pop_macro("interface") + +#endif // SWIFT_SIMPLUGIN_MSFS2024_SIMCONNECTWINDOWS_H diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024.cpp index fa9497ed3d..f0e0477d77 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024.cpp @@ -3,7 +3,7 @@ #include "simulatorMsFs2024.h" -#include "../fsxcommon/simconnectsymbols.h" +#include "../msfs2024/simconnectsymbolsmsfs2024.h" using namespace swift::misc; using namespace swift::misc::aviation; @@ -13,23 +13,23 @@ using namespace swift::misc::network; using namespace swift::misc::simulation; using namespace swift::misc::simulation::fscommon; using namespace swift::core; -using namespace swift::simplugin::fsxcommon; +using namespace swift::simplugin::msfs2024common; namespace swift::simplugin::msfs2024 { CSimulatorMsFs2024::CSimulatorMsFs2024(const CSimulatorPluginInfo &info, IOwnAircraftProvider *ownAircraftProvider, IRemoteAircraftProvider *remoteAircraftProvider, IClientProvider *clientProvider, QObject *parent) - : CSimulatorFsxCommon(info, ownAircraftProvider, remoteAircraftProvider, clientProvider, parent) + : CSimulatorMsfs2024(info, ownAircraftProvider, remoteAircraftProvider, clientProvider, parent) { - this->setDefaultModel({ "Airbus A320 Neo Asobo", CAircraftModel::TypeModelMatchingDefaultModel, + this->setDefaultModel({ "A320neo V2", CAircraftModel::TypeModelMatchingDefaultModel, "Airbus A320 default model", CAircraftIcaoCode("A320", "L2J") }); } bool CSimulatorMsFs2024::connectTo() { if (!loadAndResolveMSFS2024SimConnect()) { return false; } - return CSimulatorFsxCommon::connectTo(); + return CSimulatorMsfs2024::connectTo(); } void CSimulatorMsFs2024::setTrueAltitude(CAircraftSituation &aircraftSituation, @@ -44,7 +44,7 @@ namespace swift::simplugin::msfs2024 void CSimulatorMsFs2024Listener::startImpl() { if (!loadAndResolveMSFS2024SimConnect()) { return; } - CSimulatorFsxCommonListener::startImpl(); + CSimulatorMsfs2024Listener::startImpl(); } } // namespace swift::simplugin::msfs2024 diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024.h b/src/plugins/simulator/msfs2024/simulatormsfs2024.h index 2ca045eeea..579d04a41d 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024.h +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024.h @@ -6,12 +6,12 @@ #ifndef SWIFT_SIMPLUGIN_MSFS_SIMULATORMSFS2024_H #define SWIFT_SIMPLUGIN_MSFS_SIMULATORMSFS2024_H -#include "../fsxcommon/simulatorfsxcommon.h" +#include "../msfs2024/simulatormsfs2024common.h" namespace swift::simplugin::msfs2024 { - //! FSX simulator implementation - class CSimulatorMsFs2024 : public swift::simplugin::fsxcommon::CSimulatorFsxCommon + //! MSFS2024 simulator implementation + class CSimulatorMsFs2024 : public swift::simplugin::msfs2024common::CSimulatorMsfs2024 { Q_OBJECT @@ -27,19 +27,19 @@ namespace swift::simplugin::msfs2024 virtual bool connectTo() override; //! @} - virtual void - setTrueAltitude(swift::misc::aviation::CAircraftSituation &aircraftSituation, - const swift::simplugin::fsxcommon::DataDefinitionOwnAircraft &simulatorOwnAircraft) override; + virtual void setTrueAltitude( + swift::misc::aviation::CAircraftSituation &aircraftSituation, + const swift::simplugin::msfs2024common::DataDefinitionOwnAircraft &simulatorOwnAircraft) override; }; //! Listener for MSFS2024 - class CSimulatorMsFs2024Listener : public fsxcommon::CSimulatorFsxCommonListener + class CSimulatorMsFs2024Listener : public swift::simplugin::msfs2024common::CSimulatorMsfs2024Listener { Q_OBJECT public: //! Constructor - using CSimulatorFsxCommonListener::CSimulatorFsxCommonListener; + using CSimulatorMsfs2024Listener::CSimulatorMsfs2024Listener; protected: virtual void startImpl() override; diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp new file mode 100644 index 0000000000..33bcd7895f --- /dev/null +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp @@ -0,0 +1,3331 @@ +// SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +#include "simulatormsfs2024common.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "../fscommon/simulatorfscommonfunctions.h" +#include "simconnectsymbolsmsfs2024.h" + +#include "config/buildconfig.h" +#include "core/application.h" +#include "core/modelsetbuilder.h" +#include "core/webdataservices.h" +#include "core/webdataservicesms.h" +#include "gui/components/dbmappingcomponent.h" +#include "gui/guiapplication.h" +#include "gui/models/distributorlistmodel.h" +#include "misc/aviation/airportlist.h" +#include "misc/country.h" +#include "misc/geo/elevationplane.h" +#include "misc/logmessage.h" +#include "misc/math/mathutils.h" +#include "misc/network/textmessage.h" +#include "misc/simulation/aircraftmodel.h" +#include "misc/simulation/data/modelcaches.h" +#include "misc/simulation/distributorlist.h" +#include "misc/simulation/fscommon/aircraftcfgparser.h" +#include "misc/simulation/fscommon/bcdconversions.h" +#include "misc/simulation/fscommon/fscommonutil.h" +#include "misc/simulation/fsx/simconnectutilities.h" +#include "misc/simulation/interpolation/interpolatormulti.h" +#include "misc/simulation/settings/simulatorsettings.h" +#include "misc/simulation/simulatorplugininfo.h" +#include "misc/statusmessagelist.h" +#include "misc/threadutils.h" +#include "misc/verify.h" +#include "misc/worker.h" + +using namespace swift::config; +using namespace swift::misc; +using namespace swift::misc::aviation; +using namespace swift::misc::physical_quantities; +using namespace swift::misc::geo; +using namespace swift::misc::network; +using namespace swift::misc::math; +using namespace swift::misc::simulation; +using namespace swift::misc::simulation::data; +using namespace swift::misc::simulation::fscommon; +using namespace swift::misc::simulation::fsx; +// using namespace swift::misc::simulation::msfs2024; +using namespace swift::misc::simulation::settings; +using namespace swift::core; +using namespace swift::core::db; +using namespace swift::simplugin::fscommon; +using namespace swift::gui; +using namespace swift::gui::models; +using namespace swift::gui::components; + +namespace swift::simplugin::msfs2024common +{ + + CSimulatorMsfs2024::CSimulatorMsfs2024(const CSimulatorPluginInfo &info, IOwnAircraftProvider *ownAircraftProvider, + IRemoteAircraftProvider *remoteAircraftProvider, + IClientProvider *clientProvider, QObject *parent) + : CSimulatorFsCommon(info, ownAircraftProvider, remoteAircraftProvider, clientProvider, parent) + { + Q_ASSERT_X(ownAircraftProvider, Q_FUNC_INFO, "Missing provider"); + Q_ASSERT_X(remoteAircraftProvider, Q_FUNC_INFO, "Missing provider"); + Q_ASSERT_X(sApp, Q_FUNC_INFO, "Missing global object"); + + m_simObjectTimer.setInterval(AddPendingAircraftIntervalMs); + // default model will be set in derived class + + CSimulatorMsfs2024::registerHelp(); + connect(&m_simObjectTimer, &QTimer::timeout, this, &CSimulatorMsfs2024::timerBasedObjectAddOrRemove); + + // m_distributorPreferences = std::make_shared(); + } + + CSimulatorMsfs2024::~CSimulatorMsfs2024() { this->disconnectFrom(); } + + bool CSimulatorMsfs2024::isConnected() const { return m_simConnected && m_hSimConnect; } + + bool CSimulatorMsfs2024::isSimulating() const { return m_simSimulating && this->isConnected(); } + + bool CSimulatorMsfs2024::connectTo() + { + if (this->isConnected()) { return true; } + this->reset(); + + const HRESULT hr = SimConnect_Open(&m_hSimConnect, sApp->swiftVersionChar(), nullptr, 0, nullptr, 0); + if (isFailure(hr)) + { + // reset state as expected for unconnected + this->reset(); + return false; + } + + // set structures and move on + this->triggerAutoTraceSendId(); // we trace the init phase, so in case something goes wrong there + this->initEvents(); + this->initEventsP3D(); + this->initDataDefinitionsWhenConnected(); + + m_timerId = this->startTimer(DispatchIntervalMs); + // do not start m_addPendingAircraftTimer here, it will be started when object was added + return true; + } + + bool CSimulatorMsfs2024::disconnectFrom() + { + if (!m_simConnected) { return true; } + m_simSimulating = false; // thread as stopped, just setting the flag here avoids overhead of on onSimStopped + m_traceAutoUntilTs = -1; + m_traceSendId = false; + this->reset(); // mark as disconnected and reset all values + + if (m_hSimConnect) + { + SimConnect_Close(m_hSimConnect); + m_hSimConnect = nullptr; + m_simConnected = false; + } + + // emit status + return CSimulatorFsCommon::disconnectFrom(); + } + + bool CSimulatorMsfs2024::physicallyAddRemoteAircraft(const CSimulatedAircraft &newRemoteAircraft) + { + this->logAddingAircraftModel(newRemoteAircraft); + return this->physicallyAddRemoteAircraftImpl(newRemoteAircraft, ExternalCall); + } + + bool CSimulatorMsfs2024::updateCOMFromSwiftToSimulator(const CFrequency &newFreq, const CFrequency &lastSimFreq, + CFrequency &last25kHzSimFreq, EventIds id) + { + if (newFreq == lastSimFreq) { return false; } + + if (CComSystem::isExclusiveWithin8_33kHzChannel(newFreq) && last25kHzSimFreq.isNull()) + { + // Switch from 25 to 8.33 + // Store last 25 kHz frequency and do not send to simulator + last25kHzSimFreq = lastSimFreq; + return false; + } + + if (CComSystem::isWithin25kHzChannel(newFreq)) + { + // Send to simulator + last25kHzSimFreq.setNull(); + SimConnect_TransmitClientEvent(m_hSimConnect, 0, id, CBcdConversions::comFrequencyToBcdHz(newFreq), + SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY); + return true; + } + + // Already 8.33 -> nothing to do + return false; + } + + bool CSimulatorMsfs2024::updateOwnSimulatorCockpit(const CSimulatedAircraft &ownAircraft, + const CIdentifier &originator) + { + if (originator == this->identifier()) { return false; } + if (!this->isSimulating()) { return false; } + + // actually those data should be the same as ownAircraft + const CComSystem newCom1 = ownAircraft.getCom1System(); + const CComSystem newCom2 = ownAircraft.getCom2System(); + const CTransponder newTransponder = ownAircraft.getTransponder(); + + bool changed = false; + + changed |= updateCOMFromSwiftToSimulator(newCom1.getFrequencyActive(), m_simCom1.getFrequencyActive(), + m_lastCom1Active, EventSetCom1Active); + changed |= updateCOMFromSwiftToSimulator(newCom1.getFrequencyStandby(), m_simCom1.getFrequencyStandby(), + m_lastCom1Standby, EventSetCom1Standby); + changed |= updateCOMFromSwiftToSimulator(newCom2.getFrequencyActive(), m_simCom2.getFrequencyActive(), + m_lastCom2Active, EventSetCom2Active); + changed |= updateCOMFromSwiftToSimulator(newCom2.getFrequencyStandby(), m_simCom2.getFrequencyStandby(), + m_lastCom2Standby, EventSetCom2Standby); + + if (newTransponder.getTransponderMode() != m_simTransponder.getTransponderMode()) + { + if (m_useSbOffsets) + { + byte ident = newTransponder.isIdentifying() ? 1U : 0U; // 1 is ident + byte standby = newTransponder.isInStandby() ? 1U : 0U; // 1 is standby + HRESULT hr = s_ok(); + + hr += SimConnect_SetClientData(m_hSimConnect, ClientAreaSquawkBox, + CSimConnectDefinitions::DataClientAreaSbIdent, + SIMCONNECT_CLIENT_DATA_SET_FLAG_DEFAULT, 0, 1, &ident); + hr += SimConnect_SetClientData(m_hSimConnect, ClientAreaSquawkBox, + CSimConnectDefinitions::DataClientAreaSbStandby, + SIMCONNECT_CLIENT_DATA_SET_FLAG_DEFAULT, 0, 1, &standby); + if (isFailure(hr)) + { + this->triggerAutoTraceSendId(); + CLogMessage(this).warning(u"Setting transponder mode failed (SB offsets)"); + } + else + { + if (m_logSbOffsets) + { + const QString lm = + "SB sent: ident " % QString::number(ident) % u" standby " % QString::number(standby); + CLogMessage(this).info(lm); + } + } + changed = true; + } + else if (this->getSimulatorPluginInfo().getSimulatorInfo().isMSFS2024()) + { + DataDefinitionMSFSTransponderMode t; + t.transponderMode = (newTransponder.isInStandby() ? 1 : 4); + t.ident = newTransponder.isIdentifying(); + + HRESULT hr = s_ok(); + + hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataTransponderModeMSFS, + SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_DATA_SET_FLAG_DEFAULT, 0, + sizeof(DataDefinitionMSFSTransponderMode), &t); + + if (isFailure(hr)) { CLogMessage(this).warning(u"Setting transponder mode failed (MSFS2024)"); } + + changed = true; + } + } + + // avoid changes of cockpit back to old values due to an outdated read back value + if (changed) { m_skipCockpitUpdateCycles = SkipUpdateCyclesForCockpit; } + + // bye + return changed; + } + + bool CSimulatorMsfs2024::updateOwnSimulatorSelcal(const CSelcal &selcal, const CIdentifier &originator) + { + if (originator == this->identifier()) { return false; } + if (!this->isSimulating()) { return false; } + + //! KB 2018-11 that would need to go to updateOwnAircraftFromSimulator if the simulator ever supports SELCAL + //! KB 2018-11 als we would need to send the value to FS9/FSX (currently we only deal with it on FS9/FSX level) + m_selcal = selcal; + return false; + } + + void CSimulatorMsfs2024::displayStatusMessage(const CStatusMessage &message) const + { + QByteArray m = message.getMessage().toLatin1().constData(); + m.append('\0'); + + SIMCONNECT_TEXT_TYPE type = SIMCONNECT_TEXT_TYPE_PRINT_BLACK; + switch (message.getSeverity()) + { + case CStatusMessage::SeverityDebug: return; + case CStatusMessage::SeverityInfo: type = SIMCONNECT_TEXT_TYPE_PRINT_GREEN; break; + case CStatusMessage::SeverityWarning: type = SIMCONNECT_TEXT_TYPE_PRINT_YELLOW; break; + case CStatusMessage::SeverityError: type = SIMCONNECT_TEXT_TYPE_PRINT_RED; break; + } + const HRESULT hr = + SimConnect_Text(m_hSimConnect, type, 7.5, EventTextMessage, static_cast(m.size()), m.data()); + Q_UNUSED(hr) + } + + void CSimulatorMsfs2024::displayTextMessage(const CTextMessage &message) const + { + QByteArray m = message.asString(true, true).toLatin1().constData(); + m.append('\0'); + + SIMCONNECT_TEXT_TYPE type = SIMCONNECT_TEXT_TYPE_PRINT_BLACK; + if (message.isSupervisorMessage()) { type = SIMCONNECT_TEXT_TYPE_PRINT_RED; } + else if (message.isPrivateMessage()) { type = SIMCONNECT_TEXT_TYPE_PRINT_YELLOW; } + else if (message.isRadioMessage()) { type = SIMCONNECT_TEXT_TYPE_PRINT_GREEN; } + + const HRESULT hr = + SimConnect_Text(m_hSimConnect, type, 7.5, EventTextMessage, static_cast(m.size()), m.data()); + Q_UNUSED(hr) + } + + bool CSimulatorMsfs2024::isPhysicallyRenderedAircraft(const CCallsign &callsign) const + { + return m_simConnectObjects.contains(callsign); + } + + CCallsignSet CSimulatorMsfs2024::physicallyRenderedAircraft() const + { + CCallsignSet callsigns(m_simConnectObjects.keys()); + callsigns.push_back( + m_addAgainAircraftWhenRemoved.getCallsigns()); // not really rendered right now, but very soon + callsigns.push_back( + m_addPendingAircraft.keys()); // not really rendered, but for the logic it should look like it is + return CCallsignSet(m_simConnectObjects.keys()); + } + + CStatusMessageList CSimulatorMsfs2024::debugVerifyStateAfterAllAircraftRemoved() const + { + CStatusMessageList msgs; + if (!CBuildConfig::isLocalDeveloperDebugBuild()) { return msgs; } + msgs = CSimulatorFsCommon::debugVerifyStateAfterAllAircraftRemoved(); + if (!m_simConnectObjects.isEmpty()) + { + msgs.push_back(CStatusMessage(this).error(u"m_simConnectObjects not empty: '%1'") + << m_simConnectObjects.getAllCallsignStringsAsString(true)); + } + if (!m_simConnectObjectsPositionAndPartsTraces.isEmpty()) + { + msgs.push_back(CStatusMessage(this).error(u"m_simConnectObjectsPositionAndPartsTraces not empty: '%1'") + << m_simConnectObjectsPositionAndPartsTraces.getAllCallsignStringsAsString(true)); + } + if (!m_addAgainAircraftWhenRemoved.isEmpty()) + { + msgs.push_back(CStatusMessage(this).error(u"m_addAgainAircraftWhenRemoved not empty: '%1'") + << m_addAgainAircraftWhenRemoved.getCallsignStrings(true).join(", ")); + } + return msgs; + } + + QString CSimulatorMsfs2024::getStatisticsSimulatorSpecific() const + { + static const QString specificInfo( + "dispatch #: %1 %2 times (cur/max): %3ms (%4ms) %5ms (%6ms) %7 %8 simData#: %9"); + return specificInfo.arg(m_dispatchProcCount) + .arg(m_dispatchProcEmptyCount) + .arg(m_dispatchTimeMs) + .arg(m_dispatchProcTimeMs) + .arg(m_dispatchMaxTimeMs) + .arg(m_dispatchProcMaxTimeMs) + .arg(CSimConnectUtilities::simConnectReceiveIdToString(static_cast(m_dispatchReceiveIdMaxTime)), + requestIdToString(m_dispatchRequestIdMaxTime)) + .arg(m_requestSimObjectDataCount); + } + + bool CSimulatorMsfs2024::requestElevation(const ICoordinateGeodetic &reference, const CCallsign &aircraftCallsign) + { + // this is the 32bit FSX version, the P3D x64 is overridden! + + if (this->isShuttingDownOrDisconnected()) { return false; } + if (!this->isUsingFsxTerrainProbe()) { return false; } + if (reference.isNull()) { return false; } + const CSimConnectObject simObject = m_simConnectObjects.getOldestNotPendingProbe(); // probes round robin + if (!simObject.isConfirmedAdded()) { return false; } + m_simConnectObjects[simObject.getCallsign()].resetTimestampToNow(); // mark probe as just used + + CCoordinateGeodetic pos(reference); + pos.setGeodeticHeight(terrainProbeAltitude()); + + SIMCONNECT_DATA_INITPOSITION position = this->coordinateToFsxPosition(pos); + const HRESULT hr = this->logAndTraceSendId( + SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetPosition, + simObject.getObjectId(), 0, 0, sizeof(SIMCONNECT_DATA_INITPOSITION), + &position), + simObject, "Cannot request AI elevation", Q_FUNC_INFO, "SimConnect_SetDataOnSimObject"); + + if (isFailure(hr)) { return false; } + + const bool ok = this->requestTerrainProbeData(simObject, aircraftCallsign); + if (ok) { emit this->requestedElevation(aircraftCallsign); } + return ok; + } + + void CSimulatorMsfs2024::CacheSimObjectAndLiveries(const SIMCONNECT_RECV_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST *msg) + { + for (unsigned i = 0; i < msg->dwArraySize; ++i) + { + const SIMCONNECT_ENUMERATE_SIMOBJECT_LIVERY &element = msg->rgData[i]; + + // combine aircraft title and livery name for database search + // const QString combined = QString(element.AircraftTitle) + " " + QString(element.LiveryName); + + vSimObjectsAndLiveries.push_back( + { QString("%1 %2").arg(element.AircraftTitle, element.LiveryName).trimmed(), + QString::fromUtf8(element.AircraftTitle), QString::fromUtf8(element.LiveryName) }); + } + + if (!sSimmobjectLoadedState.bLoadStarted) + { + sSimmobjectLoadedState.bLoadStarted = true; + CLogMessage(this).info(u"Start loading SimObjects and liverys from simulator"); + + // TODO TZ a message should be displayed here because the gui freezes during loading large amounts of data + const CStatusMessage m = CStatusMessage(this, CStatusMessage::SeverityInfo, + u"Start loading SimObjects and liverys from simulator"); + } + + // Check the result set to detect the end of the transmission + switch (msg->dwRequestID) + { + case CSimConnectDefinitions::REQUEST_AIRPLANE: + if (msg->dwArraySize < 79) sSimmobjectLoadedState.bAirplaneLoaded = true; + break; + case CSimConnectDefinitions::REQUEST_HELICOPTER: + if (msg->dwArraySize < 79) sSimmobjectLoadedState.bHelicopterLoaded = true; + break; + case CSimConnectDefinitions::REQUEST_HOT_AIR: + if (msg->dwArraySize < 79) sSimmobjectLoadedState.bHotAirLoaded = true; + break; + + default: break; + } + + // sSimmobjectLoadedState.bHotAirLoaded + if (sSimmobjectLoadedState.bAirplaneLoaded && sSimmobjectLoadedState.bHelicopterLoaded) + { + sSimmobjectLoadedState.bLoadStarted = false; + size_t countmodels = vSimObjectsAndLiveries.size(); + CLogMessage(this).info(u"%1 SimObjects and Liveries loaded from SimConnect") << countmodels; + + // now we try to create a new temporary model list + setSimObjectAndLiveries(); + + CLogMessage(this).info(u"finished new model set"); + } + } + + void CSimulatorMsfs2024::setSimObjectAndLiveries() + { + // TODO TZ a message should be displayed here because the gui freezes during loading + // better: move to the background (e.g., use CWorker::fromTask(...)), avoid GUI freeze. + + this->createNewModelList(); + + CLogMessage(this).info(u"%1 SimObjects and Liveries in vSimObjectsAndLiveries") + << vSimObjectsAndLiveries.size(); + // Cannot create children for a parent that is in a different thread. + // owner = this (QObject in main thread) + // auto *worker = CWorker::fromTask(this, "createNewModelList", [=]() { + // this->createNewModelList(); + // return QVariant(); // void-Result + //}); + + // TODO TZ where to place this message? + // worker->then(this, [=] { CLogMessage(this).info(u"SimObjects and Liveries in vSimObjectsAndLiveries ready"); + // }); + } + + void CSimulatorMsfs2024::createNewModelList() + { + + const CSpecializedSimulatorSettings settings = this->getSimulatorSettings(); + CSimulatorSettings m_generic = settings.getGenericSettings(); + QStringList excludePatterns = m_generic.getModelExcludeDirectoryPatterns(); + + bool gui_application = true; + QString guiName = sGui->getApplicationName(); + if (guiName.contains("mapping")) gui_application = false; + + CAircraftModelList newModels; + + for (int i = 0; i < static_cast(vSimObjectsAndLiveries.size()); ++i) + { + const sSimObjectLivery &modelLivery = vSimObjectsAndLiveries[i]; + + CAircraftModel model; + CAircraftModel modelFromDb = + sGui->getWebDataServices()->getModelForModelString(modelLivery.szSimObjectCombinedTitle.trimmed()); + + // If the model is in the database, there is a DbKey + int modelkey = modelFromDb.getDbKey(); + if (modelkey) model = modelFromDb; // copy all data from db + + // we need the combined string of the model for further processing + model.setModelString(modelLivery.szSimObjectCombinedTitle); + model.setModelLivery(modelLivery.szLiveryName); + model.setModelType(CAircraftModel::TypeOwnSimulatorModel); + model.setSimulator(this->getSimulatorInfo()); + + bool excluded = false; + for (const QString &rawPattern : excludePatterns) + { + const QString pattern = rawPattern.trimmed(); + if (pattern.isEmpty()) continue; + if (model.getModelString().contains(pattern, Qt::CaseInsensitive)) + { + excluded = true; + break; + } + } + if (excluded) continue; // skip adding this model + + newModels.replaceOrAddModelWithString(model, Qt::CaseInsensitive); + } + + CAircraftModelList newModelList; + CAircraftModelList currentSet; + CAircraftModelList NewSet; + + // store the model in the new list + newModelList.replaceOrAddModelsWithString(newModels, Qt::CaseInsensitive); + + CLogMessage(this).info(u"%1 SimObjects and Liveries in newModelList") << newModelList.size(); + + if (!newModelList.isEmpty()) + { + + m_simulatorInfo = this->getSimulatorInfo(); + + bool givenDistributorsOnly = false; + bool dbDataOnly = false; + bool dbIcaoOnly = false; + bool incremnental = true; + bool sortByDistributor = true; + bool consolidateWithDb = false; + bool ShowAllInstalledModells = true; + + if (gui_application) + { + givenDistributorsOnly = m_generic.getPropertyDistributorFiltered(); + dbDataOnly = m_generic.getPropertyWithDbEntry(); + dbIcaoOnly = false; + incremnental = false; + sortByDistributor = true; + consolidateWithDb = true; + ShowAllInstalledModells = true; // msfs20424 always show all installed models + } + + // CDistributorList distributorList; + // for (const QString &name : distributorNames) { distributorList.push_back(CDistributor(name)); } + CDistributorList distributorList = sGui->getWebDataServices()->getDistributors(); + + const CModelSetBuilder builder(this); + CModelSetBuilder::Builder options = + givenDistributorsOnly ? CModelSetBuilder::GivenDistributorsOnly : CModelSetBuilder::NoOptions; + if (dbDataOnly) { options |= CModelSetBuilder::OnlyDbData; } + if (dbIcaoOnly) { options |= CModelSetBuilder::OnlyDbIcaoCodes; } + if (incremnental) { options |= CModelSetBuilder::Incremental; } + if (sortByDistributor) { options |= CModelSetBuilder::SortByDistributors; } + if (consolidateWithDb) { options |= CModelSetBuilder::ConsolidateWithDb; } + if (ShowAllInstalledModells) { options |= CModelSetBuilder::ShowAllInstalledModells; } + const CSimulatorInfo &simulator = this->getSimulatorInfo(); + + CCentralMultiSimulatorModelSetCachesProvider::modelCachesInstance().synchronizeCache(simulator); + currentSet = CCentralMultiSimulatorModelSetCachesProvider::modelCachesInstance().getCachedModels(simulator); + + NewSet = builder.buildModelSet(simulator, newModelList, currentSet, options, distributorList); + + CAircraftMatcher matcher; + swift::misc::simulation::CAircraftMatcherSetup mSetup = matcher.getSetup(); + + NewSet.setSimulatorInfo(simulator); + matcher.setModelSet(NewSet, m_simulatorInfo, true); + + const QDateTime latestDbModelsTs = + NewSet.isEmpty() ? sApp->getWebDataServices()->getCacheTimestamp(CEntityFlags::ModelEntity) : + NewSet.latestTimestamp(); + if (!latestDbModelsTs.isValid()) { return; } + + // for swiftgui it is enough to set the cache here + if (gui_application) + CCentralMultiSimulatorModelSetCachesProvider::modelCachesInstance().setModelsForSimulator(NewSet, + simulator); + + CCentralMultiSimulatorModelCachesProvider::modelCachesInstance().setCachedModels(NewSet, simulator); + + const CStatusMessage m = CStatusMessage(this, CStatusMessage::SeverityInfo, + u"Loading SimObjects and Liveries from the Simulator completed"); + + CLogMessage(this).info(u"%1 SimObjects and Liveries in DbModelList") << NewSet.size(); + + // TODO TZ only for debugging + // int cstoremodels = writeSimObjectsAndLiveriesToFile(NewSet); + } + } + + int CSimulatorMsfs2024::writeSimObjectsAndLiveriesToFile(CAircraftModelList Modelset) + { + + int counter = 0; + const std::string dateiname = "aircraftlist.txt"; + std::ofstream datei(dateiname, std::ios::out); + if (!datei) return 0; + for (int i = 0; i < static_cast(Modelset.size()); ++i) + { + datei << Modelset[i].getShortModelString().toStdString() + << "::" << Modelset[i].getModelLivery().toStdString() << "::" << Modelset[i].getDbKey() << std::endl; + ++counter; + } + datei.close(); + return counter; + } + + bool CSimulatorMsfs2024::isTracingSendId() const + { + if (m_traceSendId) { return true; } // explicit + if (m_traceAutoUntilTs < 0) { return false; } // no auto + const qint64 ts = QDateTime::currentMSecsSinceEpoch(); + const bool trace = ts <= m_traceAutoUntilTs; + return trace; + } + + void CSimulatorMsfs2024::setTractingSendId(bool trace) + { + m_traceSendId = trace; + m_traceAutoUntilTs = -1; + } + + void CSimulatorMsfs2024::setAddingAsSimulatedObjectEnabled(bool enabled) + { + m_useAddSimulatedObj = enabled; + const CSimulatorInfo sim = this->getSimulatorInfo(); + CFsxP3DSettings settings = m_detailsSettings.getSettings(sim); + settings.setAddingAsSimulatedObjectEnabled(enabled); + m_detailsSettings.setSettings(settings, sim); + } + + void CSimulatorMsfs2024::setUsingSbOffsetValues(bool enabled) + { + m_useSbOffsets = enabled; + const CSimulatorInfo sim = this->getSimulatorInfo(); + CFsxP3DSettings settings = m_detailsSettings.getSettings(sim); + settings.setSbOffsetsEnabled(enabled); + m_detailsSettings.setSettings(settings, sim); + } + + void CSimulatorMsfs2024::resetAircraftStatistics() + { + m_dispatchProcCount = 0; + m_dispatchProcEmptyCount = 0; + m_dispatchMaxTimeMs = -1; + m_dispatchProcMaxTimeMs = -1; + m_dispatchTimeMs = -1; + m_dispatchProcTimeMs = -1; + m_requestSimObjectDataCount = 0; + m_dispatchReceiveIdLast = SIMCONNECT_RECV_ID_NULL; + m_dispatchReceiveIdMaxTime = SIMCONNECT_RECV_ID_NULL; + m_dispatchRequestIdLast = CSimConnectDefinitions::RequestEndMarker; + m_dispatchRequestIdMaxTime = CSimConnectDefinitions::RequestEndMarker; + CSimulatorPluginCommon::resetAircraftStatistics(); + } + + void CSimulatorMsfs2024::setFlightNetworkConnected(bool connected) + { + // toggled? + if (connected == !this->isFlightNetworkConnected()) + { + // toggling, we trace for a while to better monitor those "critical" phases + this->triggerAutoTraceSendId(); + } + + // update SB area network connected + byte sbNetworkConnected = connected ? 1u : 0u; + const HRESULT hr = SimConnect_SetClientData(m_hSimConnect, ClientAreaSquawkBox, + CSimConnectDefinitions::DataClientAreaSbConnected, + SIMCONNECT_CLIENT_DATA_SET_FLAG_DEFAULT, 0, 1, &sbNetworkConnected); + if (isFailure(hr)) { CLogMessage(this).warning(u"Setting network connected failed (SB offsets)"); } + + ISimulator::setFlightNetworkConnected(connected); + } + + CStatusMessageList CSimulatorMsfs2024::getInterpolationMessages(const CCallsign &callsign) const + { + if (!m_simConnectObjects.contains(callsign)) { return CStatusMessageList(); } + const CInterpolationAndRenderingSetupPerCallsign setup = + this->getInterpolationSetupConsolidated(callsign, false); + return (m_simConnectObjects[callsign]).getInterpolationMessages(setup.getInterpolatorMode()); + } + + bool CSimulatorMsfs2024::testSendSituationAndParts(const CCallsign &callsign, const CAircraftSituation &situation, + const CAircraftParts &parts) + { + if (!m_simConnectObjects.contains(callsign)) { return false; } + CSimConnectObject simObject = m_simConnectObjects.value(callsign); + int u = 0; + if (!parts.isNull()) + { + this->sendRemoteAircraftPartsToSimulator(simObject, parts); + u++; + } + if (!situation.isNull()) + { + SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToFsxPosition(situation, true); + const bool traceSendId = this->isTracingSendId(); + const HRESULT hr = this->logAndTraceSendId( + SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetPosition, + static_cast(simObject.getObjectId()), 0, 0, + sizeof(SIMCONNECT_DATA_INITPOSITION), &position), + traceSendId, simObject, "Failed to set position", Q_FUNC_INFO, "SimConnect_SetDataOnSimObject"); + if (hr == S_OK) { u++; } + } + return u > 0; + } + + CSimConnectDefinitions::SimObjectRequest CSimulatorMsfs2024::requestToSimObjectRequest(DWORD requestId) + { + DWORD v = static_cast(CSimConnectDefinitions::SimObjectEndMarker); + if (isRequestForSimObjAircraft(requestId)) { v = (requestId - RequestSimObjAircraftStart) / MaxSimObjAircraft; } + else if (isRequestForSimObjTerrainProbe(requestId)) + { + v = (requestId - RequestSimObjTerrainProbeStart) / MaxSimObjProbes; + } + Q_ASSERT_X(v <= CSimConnectDefinitions::SimObjectEndMarker, Q_FUNC_INFO, "Invalid value"); + return static_cast(v); + } + + bool CSimulatorMsfs2024::stillDisplayReceiveExceptions() + { + m_receiveExceptionCount++; + return m_receiveExceptionCount < IgnoreReceiveExceptions; + } + + CSimConnectObject CSimulatorMsfs2024::getSimObjectForObjectId(DWORD objectId) const + { + return this->getSimConnectObjects().getSimObjectForObjectId(objectId); + } + + void CSimulatorMsfs2024::setSimConnected() + { + m_simConnected = true; + this->initSimulatorInternals(); + this->emitSimulatorCombinedStatus(); + + // Internals depends on simulator data which take a while to be read + // this is a trick and I re-init again after a while (which is not really expensive) + const QPointer myself(this); + QTimer::singleShot(2500, this, [myself] { + if (!myself) { return; } + myself->initSimulatorInternals(); + }); + } + + void CSimulatorMsfs2024::onSimRunning() + { + const QPointer myself(this); + QTimer::singleShot(DeferSimulatingFlagMs, this, [=] { + if (!myself) { return; } + m_simulatingChangedTs = QDateTime::currentMSecsSinceEpoch(); + this->onSimRunningDeferred(m_simulatingChangedTs); + }); + } + + void CSimulatorMsfs2024::onSimRunningDeferred(qint64 referenceTs) + { + if (m_simSimulating) { return; } // already simulatig + if (referenceTs != m_simulatingChangedTs) { return; } // changed, so no longer valid + m_simSimulating = true; // only place where this should be set to true + m_simConnected = true; + + const CFsxP3DSettings settings = m_detailsSettings.getSettings(this->getSimulatorInfo()); + m_useAddSimulatedObj = settings.isAddingAsSimulatedObjectEnabled(); + m_useSbOffsets = settings.isSbOffsetsEnabled(); + if (this->getSimulatorPluginInfo().getSimulatorInfo().isMSFS2024()) + { + m_useSbOffsets = false; // Always disable SbOffsets for MSFS. Using new transponder mode property directly + } + + HRESULT hr = s_ok(); + hr += this->logAndTraceSendId( + SimConnect_RequestDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::RequestOwnAircraft, + CSimConnectDefinitions::DataOwnAircraft, SIMCONNECT_OBJECT_ID_USER, + SIMCONNECT_PERIOD_VISUAL_FRAME), + "Cannot request own aircraft data", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); + + hr += this->logAndTraceSendId( + SimConnect_RequestDataOnSimObjectType(m_hSimConnect, CSimConnectDefinitions::RequestOwnAircraftTitle, + CSimConnectDefinitions::DataOwnAircraftTitle, 0, + SIMCONNECT_SIMOBJECT_TYPE_USER), + "Cannot request title and livery", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObjectType"); + + hr += this->logAndTraceSendId(SimConnect_RequestDataOnSimObject( + m_hSimConnect, CSimConnectDefinitions::RequestMSFSTransponder, + CSimConnectDefinitions::DataTransponderModeMSFS, SIMCONNECT_OBJECT_ID_USER, + SIMCONNECT_PERIOD_VISUAL_FRAME, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED), + "Cannot request MSFS transponder data", Q_FUNC_INFO, + "SimConnect_RequestDataOnSimObject"); + + if (isFailure(hr)) { return; } + this->emitSimulatorCombinedStatus(); // force sending status + } + + void CSimulatorMsfs2024::onSimStopped() + { + // stopping events in FSX: Load menu, weather and season + CLogMessage(this).info(u"Simulator stopped: %1") << this->getSimulatorDetails(); + const SimulatorStatus oldStatus = this->getSimulatorStatus(); + m_simSimulating = false; + m_simulatingChangedTs = QDateTime::currentMSecsSinceEpoch(); + this->emitSimulatorCombinedStatus(oldStatus); + } + + void CSimulatorMsfs2024::onSimFrame() + { + if (m_updateRemoteAircraftInProgress) { return; } + QPointer myself(this); + QTimer::singleShot(0, this, [=] { + // run decoupled from simconnect event queue + if (!myself) { return; } + myself->updateRemoteAircraft(); + }); + } + + void CSimulatorMsfs2024::onSimExit() + { + CLogMessage(this).info(u"Simulator exit: %1") << this->getSimulatorDetails(); + + // reset complete state, we are going down + m_simulatingChangedTs = QDateTime::currentMSecsSinceEpoch(); + this->safeKillTimer(); + + // if called from dispatch function, avoid that SimConnectProc disconnects itself while in SimConnectProc + QPointer myself(this); + QTimer::singleShot(0, this, [=] { + if (!myself) { return; } + this->disconnectFrom(); + }); + } + + SIMCONNECT_DATA_REQUEST_ID CSimulatorMsfs2024::obtainRequestIdForSimObjAircraft() + { + const SIMCONNECT_DATA_REQUEST_ID id = m_requestIdSimObjAircraft++; + if (id > RequestSimObjAircraftEnd) { m_requestIdSimObjAircraft = RequestSimObjAircraftStart; } + return id; + } + + SIMCONNECT_DATA_REQUEST_ID CSimulatorMsfs2024::obtainRequestIdForSimObjTerrainProbe() + { + const SIMCONNECT_DATA_REQUEST_ID id = m_requestIdSimObjTerrainProbe++; + if (id > RequestSimObjTerrainProbeEnd) { m_requestIdSimObjTerrainProbe = RequestSimObjTerrainProbeStart; } + return id; + } + + bool CSimulatorMsfs2024::releaseAIControl(const CSimConnectObject &simObject, SIMCONNECT_DATA_REQUEST_ID requestId) + { + const SIMCONNECT_OBJECT_ID objectId = simObject.getObjectId(); + const HRESULT hr1 = + this->logAndTraceSendId(SimConnect_AIReleaseControl(m_hSimConnect, objectId, requestId), simObject, + "Release control", Q_FUNC_INFO, "SimConnect_AIReleaseControl"); + const HRESULT hr2 = + this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventFreezeLatLng, 1, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + simObject, "EventFreezeLatLng", Q_FUNC_INFO, "SimConnect_TransmitClientEvent"); + const HRESULT hr3 = + this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventFreezeAlt, 1, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + simObject, "EventFreezeAlt", Q_FUNC_INFO, "SimConnect_TransmitClientEvent"); + const HRESULT hr4 = + this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventFreezeAtt, 1, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + simObject, "EventFreezeAtt", Q_FUNC_INFO, "SimConnect_TransmitClientEvent"); + + return isOk(hr1, hr2, hr3, hr4); + } + + bool CSimulatorMsfs2024::isValidSimObjectNotPendingRemoved(const CSimConnectObject &simObject) const + { + if (!simObject.hasValidRequestAndObjectId()) { return false; } + if (simObject.isPendingRemoved()) { return false; } + if (!m_simConnectObjects.contains(simObject.getCallsign())) { return false; } // removed in meantime + return true; + } + + CSimConnectObject CSimulatorMsfs2024::getSimObjectForTrace(const TraceFsxSendId &trace) const + { + return m_simConnectObjects.getSimObjectForOtherSimObject(trace.simObject); + } + + bool CSimulatorMsfs2024::removeSimObjectForTrace(const TraceFsxSendId &trace) + { + return m_simConnectObjects.removeByOtherSimObject(trace.simObject); + } + + void CSimulatorMsfs2024::removeCamera(CSimConnectObject &simObject) + { + // not in FSX + Q_UNUSED(simObject) + } + + void CSimulatorMsfs2024::removeObserver(CSimConnectObject &simObject) + { + // not in FSX + Q_UNUSED(simObject) + } + + bool CSimulatorMsfs2024::triggerAutoTraceSendId(qint64 traceTimeMs) + { + if (m_traceSendId) { return false; } // no need + if (this->isShuttingDownOrDisconnected()) { return false; } + const qint64 ts = QDateTime::currentMSecsSinceEpoch(); + const qint64 traceUntil = traceTimeMs + ts; + if (traceUntil <= m_traceAutoUntilTs) { return false; } + m_traceAutoUntilTs = traceUntil; + + static const QString format("hh:mm:ss.zzz"); + const QString untilString = QDateTime::fromMSecsSinceEpoch(traceUntil).toString(format); + CLogMessage(this).info(u"Triggered FSX/P3D auto trace until %1") << untilString; + const QPointer myself(this); + QTimer::singleShot(traceTimeMs * 1.2, this, [=] { + // triggered by mself (ts check), otherwise ignore + if (!myself) { return; } + if (m_traceAutoUntilTs > QDateTime::currentMSecsSinceEpoch()) { return; } + if (m_traceAutoUntilTs < 0) { return; } // alread off + CLogMessage(this).info(u"Auto trace id off"); + m_traceAutoUntilTs = -1; + }); + return true; + } + + void CSimulatorMsfs2024::setTrueAltitude(CAircraftSituation &aircraftSituation, + const DataDefinitionOwnAircraft &simulatorOwnAircraft) + { + aircraftSituation.setAltitude( + CAltitude(simulatorOwnAircraft.altitudeFt, CAltitude::MeanSeaLevel, CLengthUnit::ft())); + } + + void CSimulatorMsfs2024::updateOwnAircraftFromSimulator(const DataDefinitionOwnAircraft &simulatorOwnAircraft) + { + const qint64 ts = QDateTime::currentMSecsSinceEpoch(); + + CSimulatedAircraft myAircraft(getOwnAircraft()); + CCoordinateGeodetic position; + position.setLatitude(CLatitude(simulatorOwnAircraft.latitudeDeg, CAngleUnit::deg())); + position.setLongitude(CLongitude(simulatorOwnAircraft.longitudeDeg, CAngleUnit::deg())); + + if (simulatorOwnAircraft.pitchDeg < -90.0 || simulatorOwnAircraft.pitchDeg >= 90.0) + { + CLogMessage(this).warning(u"FSX: Pitch value (own aircraft) out of limits: %1") + << simulatorOwnAircraft.pitchDeg; + } + CAircraftSituation aircraftSituation; + aircraftSituation.setMSecsSinceEpoch(ts); + aircraftSituation.setPosition(position); + // MSFS has inverted pitch and bank angles + aircraftSituation.setPitch(CAngle(-simulatorOwnAircraft.pitchDeg, CAngleUnit::deg())); + aircraftSituation.setBank(CAngle(-simulatorOwnAircraft.bankDeg, CAngleUnit::deg())); + aircraftSituation.setHeading(CHeading(simulatorOwnAircraft.trueHeadingDeg, CHeading::True, CAngleUnit::deg())); + aircraftSituation.setGroundSpeed(CSpeed(simulatorOwnAircraft.velocity, CSpeedUnit::kts())); + aircraftSituation.setGroundElevation( + CAltitude(simulatorOwnAircraft.elevationFt, CAltitude::MeanSeaLevel, CLengthUnit::ft()), + CAircraftSituation::FromProvider); + setTrueAltitude(aircraftSituation, simulatorOwnAircraft); + aircraftSituation.setPressureAltitude(CAltitude(simulatorOwnAircraft.pressureAltitudeM, CAltitude::MeanSeaLevel, + CAltitude::PressureAltitude, CLengthUnit::m())); + // set on ground also in situation for consistency and future usage + // it is duplicated in parts + aircraftSituation.setOnGroundInfo( + { dtb(simulatorOwnAircraft.simOnGround) ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround, + COnGroundInfo::OutOnGroundOwnAircraft }); + + CAircraftVelocity aircraftVelocity( + simulatorOwnAircraft.velocityWorldX, simulatorOwnAircraft.velocityWorldY, + simulatorOwnAircraft.velocityWorldZ, CSpeedUnit::ft_s(), simulatorOwnAircraft.rotationVelocityBodyX, + simulatorOwnAircraft.rotationVelocityBodyZ, simulatorOwnAircraft.rotationVelocityBodyY, CAngleUnit::rad(), + CTimeUnit::s()); + aircraftSituation.setVelocity(aircraftVelocity); + + const CAircraftLights lights(dtb(simulatorOwnAircraft.lightStrobe), dtb(simulatorOwnAircraft.lightLanding), + dtb(simulatorOwnAircraft.lightTaxi), dtb(simulatorOwnAircraft.lightBeacon), + dtb(simulatorOwnAircraft.lightNav), dtb(simulatorOwnAircraft.lightLogo)); + + CAircraftEngineList engines; + const QList helperList { dtb(simulatorOwnAircraft.engine1Combustion), + dtb(simulatorOwnAircraft.engine2Combustion), + dtb(simulatorOwnAircraft.engine3Combustion), + dtb(simulatorOwnAircraft.engine4Combustion) }; + + for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index) + { + engines.push_back(CAircraftEngine(index + 1, helperList.value(index, true))); + } + + const CAircraftParts parts(lights, dtb(simulatorOwnAircraft.gearHandlePosition), + qRound(simulatorOwnAircraft.flapsHandlePosition * 100), + dtb(simulatorOwnAircraft.spoilersHandlePosition), engines, + dtb(simulatorOwnAircraft.simOnGround), ts); + + // set values + this->updateOwnSituationAndGroundElevation(aircraftSituation); + this->updateOwnParts(parts); + + // When I change cockpit values in the sim (from GUI to simulator, not originating from simulator) + // it takes a little while before these values are set in the simulator. + // To avoid jitters, I wait some update cylces to stabilize the values + if (m_skipCockpitUpdateCycles < 1) + { + // defaults + CComSystem com1(myAircraft.getCom1System()); // set defaults + CComSystem com2(myAircraft.getCom2System()); + + // updates: + // https://www.fsdeveloper.com/forum/threads/com-unit-receiving-status-com-transmit-x-com-test-1-and-volume.445187/ + // COM: If you're set to transmit on a unit, you WILL receive that unit. + // Otherwise if you're NOT set to transmit on a unit, then it will only receive if COM RECEIVE ALL is + // true. There is no control of COM volume. + com1.setFrequencyActive(CFrequency(simulatorOwnAircraft.com1ActiveMHz, CFrequencyUnit::MHz())); + com1.setFrequencyStandby(CFrequency(simulatorOwnAircraft.com1StandbyMHz, CFrequencyUnit::MHz())); + const bool comReceiveAll = dtb(simulatorOwnAircraft.comReceiveAll); + const bool com1Test = dtb(simulatorOwnAircraft.comTest1); + const bool com1Transmit = dtb(simulatorOwnAircraft.comTransmit1); + const int com1Status = + qRound(simulatorOwnAircraft.comStatus1); // Radio status flag : -1 =Invalid 0 = OK 1 = + // Does not exist 2 = No electricity 3 = Failed + com1.setTransmitEnabled(com1Status == 0 && com1Transmit); + com1.setReceiveEnabled(com1Status == 0 && (comReceiveAll || com1Transmit)); + + const bool changedCom1Active = + myAircraft.getCom1System().getFrequencyActive() != com1.getFrequencyActive() && + com1.getFrequencyActive() != m_lastCom1Active; + const bool changedCom1Standby = + myAircraft.getCom1System().getFrequencyStandby() != com1.getFrequencyStandby() && + com1.getFrequencyStandby() != m_lastCom1Standby; + + // Avoid overwrite of 8.33 kHz frequency with data from simulator + if (!changedCom1Active) { com1.setFrequencyActive(myAircraft.getCom1System().getFrequencyActive()); } + else { m_lastCom1Active.setNull(); } + + if (!changedCom1Standby) { com1.setFrequencyStandby(myAircraft.getCom1System().getFrequencyStandby()); } + else { m_lastCom1Standby.setNull(); } + + const bool changedCom1 = myAircraft.getCom1System() != com1; + + m_simCom1 = com1; + Q_UNUSED(com1Test) + + com2.setFrequencyActive(CFrequency(simulatorOwnAircraft.com2ActiveMHz, CFrequencyUnit::MHz())); + com2.setFrequencyStandby(CFrequency(simulatorOwnAircraft.com2StandbyMHz, CFrequencyUnit::MHz())); + const bool com2Test = dtb(simulatorOwnAircraft.comTest2); + const bool com2Transmit = dtb(simulatorOwnAircraft.comTransmit2); + const int com2Status = + qRound(simulatorOwnAircraft.comStatus2); // Radio status flag : -1 =Invalid 0 = OK 1 = + // Does not exist 2 = No electricity 3 = Failed + com2.setTransmitEnabled(com2Status == 0 && com2Transmit); + com2.setReceiveEnabled(com2Status == 0 && (comReceiveAll || com2Transmit)); + const bool changedCom2Active = + myAircraft.getCom2System().getFrequencyActive() != com2.getFrequencyActive() && + com2.getFrequencyActive() != m_lastCom2Active; + const bool changedCom2Standby = + myAircraft.getCom2System().getFrequencyStandby() != com2.getFrequencyStandby() && + com2.getFrequencyStandby() != m_lastCom2Standby; + + // Avoid overwrite of 8.33 kHz frequency with data from simulator + if (!changedCom2Active) { com2.setFrequencyActive(myAircraft.getCom2System().getFrequencyActive()); } + else { m_lastCom2Active.setNull(); } + + if (!changedCom2Standby) { com2.setFrequencyStandby(myAircraft.getCom2System().getFrequencyStandby()); } + else { m_lastCom2Standby.setNull(); } + + const bool changedCom2 = myAircraft.getCom2System() != com2; + + m_simCom2 = com2; + Q_UNUSED(com2Test) + + CTransponder transponder(myAircraft.getTransponder()); + transponder.setTransponderCode(qRound(simulatorOwnAircraft.transponderCode)); + m_simTransponder = transponder; + + // if the simulator ever sends SELCAL, add it here. + // m_selcal SELCAL sync.would go here + + const bool changedXpr = (myAircraft.getTransponderCode() != transponder.getTransponderCode()); + + if (changedCom1 || changedCom2 || changedXpr) + { + // set in own aircraft provider + this->updateCockpit(com1, com2, transponder, identifier()); + } + } + else { --m_skipCockpitUpdateCycles; } + + // slower updates + if (m_ownAircraftUpdateCycles % 10 == 0) + { + // init terrain probes here has the advantage we can also switch it on/off at runtime + if (m_useFsxTerrainProbe && !m_initFsxTerrainProbes) + { + this->physicallyInitAITerrainProbes(position, 2); // init probe + } + + // SB3 offsets updating + m_simulatorInternals.setValue(QStringLiteral("fsx/sb3"), boolToEnabledDisabled(m_useSbOffsets)); + m_simulatorInternals.setValue(QStringLiteral("fsx/sb3packets"), m_useSbOffsets ? + QString::number(m_sbDataReceived) : + QStringLiteral("disabled")); + + // CG + const CLength cg(simulatorOwnAircraft.cgToGroundFt, CLengthUnit::ft()); + this->updateOwnCG(cg); + + // Simulated objects instead of NON ATC + m_simulatorInternals.setValue(QStringLiteral("fsx/addAsSimulatedObject"), + boolToEnabledDisabled(m_useAddSimulatedObj)); + + } // slow updates + + m_ownAircraftUpdateCycles++; // with 50 updates/sec long enough even for 32bit + } + + void CSimulatorMsfs2024::triggerUpdateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, + const DataDefinitionPosData &remoteAircraftData) + { + if (this->isShuttingDownOrDisconnected()) { return; } + QPointer myself(this); + QTimer::singleShot(0, this, [=] { + if (!myself) { return; } + myself->updateRemoteAircraftFromSimulator(simObject, remoteAircraftData); + }); + } + + void CSimulatorMsfs2024::triggerUpdateRemoteAircraftFromSimulator( + const CSimConnectObject &simObject, const DataDefinitionRemoteAircraftModel &remoteAircraftModel) + { + if (this->isShuttingDownOrDisconnected()) { return; } + QPointer myself(this); + QTimer::singleShot(0, this, [=] { + if (!myself) { return; } + myself->updateRemoteAircraftFromSimulator(simObject, remoteAircraftModel); + }); + } + + void CSimulatorMsfs2024::updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, + const DataDefinitionPosData &remoteAircraftData) + { + if (this->isShuttingDownOrDisconnected()) { return; } + + // Near ground we use faster updates + const CCallsign cs(simObject.getCallsign()); + CAircraftSituation lastSituation = m_lastSentSituations[cs]; + const bool moving = lastSituation.isMoving(); + const bool onGround = remoteAircraftData.isOnGround(); + + // CElevationPlane: deg, deg, feet + // we only remember near ground + const CElevationPlane elevation = + CElevationPlane(remoteAircraftData.latitudeDeg, remoteAircraftData.longitudeDeg, + remoteAircraftData.elevationFt, CElevationPlane::singlePointRadius()); + if (remoteAircraftData.aboveGroundFt() < 250) + { + const CLength cg(remoteAircraftData.cgToGroundFt, CLengthUnit::ft()); + this->rememberElevationAndSimulatorCG(cs, simObject.getAircraftModel(), onGround, elevation, cg); + } + + const bool log = this->isLogCallsign(cs); + if (log) + { + // update lat/lng/alt with real data from sim + const CAltitude alt(remoteAircraftData.altitudeFt, CAltitude::MeanSeaLevel, CAltitude::TrueAltitude, + CLengthUnit::ft()); + lastSituation.setPosition(elevation); + lastSituation.setAltitude(alt); + lastSituation.setGroundElevation(elevation, CAircraftSituation::FromProvider); + this->addLoopbackSituation(lastSituation); + } + + if (moving && remoteAircraftData.aboveGroundFt() <= 100.0) + { + // switch to fast updates + if (simObject.getSimDataPeriod() != SIMCONNECT_PERIOD_VISUAL_FRAME) + { + this->requestPositionDataForSimObject(simObject, SIMCONNECT_PERIOD_VISUAL_FRAME); + } + } + else + { + // switch to slow updates + if (simObject.getSimDataPeriod() != SIMCONNECT_PERIOD_SECOND) + { + this->requestPositionDataForSimObject(simObject, SIMCONNECT_PERIOD_SECOND); + } + } + } + + void + CSimulatorMsfs2024::updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, + const DataDefinitionRemoteAircraftModel &remoteAircraftModel) + { + const CCallsign cs(simObject.getCallsign()); + if (!m_simConnectObjects.contains(cs)) { return; } // no longer existing + CSimConnectObject &so = m_simConnectObjects[cs]; + if (so.isPendingRemoved()) { return; } + + const QString modelString(remoteAircraftModel.title); + const CLength cg(remoteAircraftModel.cgToGroundFt, CLengthUnit::ft()); + so.setAircraftCG(cg); + so.setAircraftModelString(modelString); + + // update in 2 providers + this->rememberElevationAndSimulatorCG(cs, simObject.getAircraftModel(), false, CElevationPlane::null(), + cg); // env. provider + this->updateCGAndModelString(cs, cg, modelString); // remote aircraft provider + } + + void CSimulatorMsfs2024::updateProbeFromSimulator(const CCallsign &callsign, + const DataDefinitionPosData &remoteAircraftData) + { + const CElevationPlane elevation(remoteAircraftData.latitudeDeg, remoteAircraftData.longitudeDeg, + remoteAircraftData.elevationFt, CElevationPlane::singlePointRadius()); + this->callbackReceivedRequestedElevation(elevation, callsign, false); + } + + void CSimulatorMsfs2024::updateOwnAircraftFromSimulator(const DataDefinitionClientAreaSb &sbDataArea) + { + if (m_skipCockpitUpdateCycles > 0) { return; } + + // log SB offset + if (m_logSbOffsets) { CLogMessage(this).info(u"SB from sim: " % sbDataArea.toQString()); } + + // SB XPDR mode + CTransponder::TransponderMode newMode = CTransponder::StateIdent; + if (!sbDataArea.isIdent()) + { + newMode = sbDataArea.isStandby() ? CTransponder::StateStandby : CTransponder::ModeC; + } + const CSimulatedAircraft myAircraft(this->getOwnAircraft()); + const bool changed = (myAircraft.getTransponderMode() != newMode); + if (!changed) { return; } + CTransponder xpdr = myAircraft.getTransponder(); + xpdr.setTransponderMode(newMode); + this->updateCockpit(myAircraft.getCom1System(), myAircraft.getCom2System(), xpdr, this->identifier()); + } + + void CSimulatorMsfs2024::updateTransponderMode(const CTransponder::TransponderMode xpdrMode) + { + if (m_skipCockpitUpdateCycles > 0) { return; } + const CSimulatedAircraft myAircraft(this->getOwnAircraft()); + const bool changed = (myAircraft.getTransponderMode() != xpdrMode); + if (!changed) { return; } + CTransponder myXpdr = myAircraft.getTransponder(); + myXpdr.setTransponderMode(xpdrMode); + this->updateCockpit(myAircraft.getCom1System(), myAircraft.getCom2System(), myXpdr, this->identifier()); + } + + void CSimulatorMsfs2024::updateMSFSTransponderMode(const DataDefinitionMSFSTransponderMode transponderMode) + { + auto mode = CTransponder::StateIdent; + if (!transponderMode.ident) + { + qRound(transponderMode.transponderMode) >= 3 ? mode = CTransponder::ModeC : + mode = CTransponder::StateStandby; + } + this->updateTransponderMode(mode); + } + + bool CSimulatorMsfs2024::simulatorReportedObjectAdded(DWORD objectId) + { + if (this->isShuttingDownOrDisconnected()) { return true; } // pretend everything is fine + const CSimConnectObject simObject = m_simConnectObjects.getSimObjectForObjectId(objectId); + const CCallsign callsign(simObject.getCallsign()); + if (!simObject.hasValidRequestAndObjectId() || callsign.isEmpty()) { return false; } + + // we know the object has been created. But it can happen it is directly removed afterwards + const CSimulatedAircraft verifyAircraft(simObject.getAircraft()); + const QPointer myself(this); + QTimer::singleShot(1000, this, [=] { + // verify aircraft and also triggers new add if required + // do not do this in the event loop, so we do this deferred + if (!myself || this->isShuttingDownOrDisconnected()) { return; } + this->verifyAddedRemoteAircraft(verifyAircraft); + }); + return true; + } + + void CSimulatorMsfs2024::verifyAddedRemoteAircraft(const CSimulatedAircraft &remoteAircraftIn) + { + if (this->isShuttingDownOrDisconnected()) { return; } + if (remoteAircraftIn.isTerrainProbe()) + { + this->verifyAddedTerrainProbe(remoteAircraftIn); + return; + } + + CStatusMessage msg; + CSimulatedAircraft remoteAircraft = remoteAircraftIn; + const CCallsign callsign(remoteAircraft.getCallsign()); + + do { + // no callsign + if (callsign.isEmpty()) + { + msg = CLogMessage(this).error(u"Cannot confirm AI object, empty callsign"); + break; + } + + // removed in meantime + const bool aircraftStillInRange = this->isAircraftInRange(callsign); + if (!m_simConnectObjects.contains(callsign)) + { + if (aircraftStillInRange) + { + msg = CLogMessage(this).warning( + u"Callsign '%1' removed in meantime from AI objects, but still in range") + << callsign.toQString(); + } + else + { + this->removeFromAddPendingAndAddAgainAircraft(callsign); + msg = CLogMessage(this).info(u"Callsign '%1' removed in meantime and no longer in range") + << callsign.toQString(); + } + break; + } + + CSimConnectObject &simObject = m_simConnectObjects[callsign]; + remoteAircraft = simObject.getAircraft(); // update, if something has changed + + if (!simObject.hasValidRequestAndObjectId() || simObject.isPendingRemoved()) + { + msg = CStatusMessage(this).warning(u"Object for callsign '%1'/id: %2 removed in meantime/invalid") + << callsign.toQString() << simObject.getObjectId(); + break; + } + + // P3D also has SimConnect_AIReleaseControlEx which also allows to destroy the aircraft + const SIMCONNECT_DATA_REQUEST_ID requestReleaseId = this->obtainRequestIdForSimObjAircraft(); + const bool released = this->releaseAIControl(simObject, requestReleaseId); + + if (!released) + { + msg = CStatusMessage(this).error(u"Cannot confirm model '%1' %2") + << remoteAircraft.getModelString() << simObject.toQString(); + break; + } + + // confirm as added, this is also required to request light, etc + Q_ASSERT_X(simObject.isPendingAdded(), Q_FUNC_INFO, "Already confirmed, this should be the only place"); + simObject.setConfirmedAdded(true); // aircraft + + // request data on object + this->requestPositionDataForSimObject(simObject); + this->requestLightsForSimObject(simObject); + this->requestModelInfoForSimObject(simObject); + + this->removeFromAddPendingAndAddAgainAircraft(callsign); // no longer try to add + const bool updated = this->updateAircraftRendered(callsign, true); + if (updated) + { + static const QString debugMsg("CS: '%1' model: '%2' verified, request/object id: %3 %4"); + if (this->showDebugLogMessage()) + { + this->debugLogMessage(Q_FUNC_INFO, + debugMsg.arg(callsign.toQString(), remoteAircraft.getModelString()) + .arg(simObject.getRequestId()) + .arg(simObject.getObjectId())); + } + + this->sendRemoteAircraftAtcDataToSimulator(simObject); + emit this->aircraftRenderingChanged(simObject.getAircraft()); + } + else + { + CLogMessage(this).warning( + u"Verified aircraft '%1' model '%2', request/object id: %3 %4 was already marked rendered") + << callsign.asString() << remoteAircraft.getModelString() << simObject.getRequestId() + << simObject.getObjectId(); + } + + if (simObject.isConfirmedAdded() && simObject.getType() == CSimConnectObject::AircraftSimulatedObject) + { + CLogMessage(this).warning(u"Confirm added model '%1' '%2', but as '%3'") + << remoteAircraft.getCallsignAsString() << remoteAircraft.getModelString() + << simObject.getTypeAsString(); + this->triggerAutoTraceSendId(); // trace for some time (issues regarding this workaround?) + simObject.decreaseAddingExceptions(); // if previously increased and now working, reset + } + } + while (false); + + // log errors and emit signal + if (!msg.isEmpty() && msg.isWarningOrAbove()) + { + CLogMessage::preformatted(msg); + emit this->physicallyAddingRemoteModelFailed(CSimulatedAircraft(), false, false, msg); + } + + // trigger adding pending aircraft if there are any + if (!m_addPendingAircraft.isEmpty()) { this->addPendingAircraftAfterAdded(); } + } + + void CSimulatorMsfs2024::addingAircraftFailed(const CSimConnectObject &simObject) + { + if (CBuildConfig::isLocalDeveloperDebugBuild()) + { + Q_ASSERT_X(simObject.isAircraft(), Q_FUNC_INFO, "Need aircraft"); + } + if (!simObject.isAircraft()) { return; } + + // clean up + m_simConnectObjects.removeByOtherSimObject(simObject); + this->removeFromAddPendingAndAddAgainAircraft(simObject.getCallsign()); + + CLogMessage(this).warning(u"Model failed to be added: '%1' details: %2") + << simObject.getAircraftModelString() << simObject.getAircraft().toQString(true); + CStatusMessage verifyMsg; + const bool verifiedAircraft = this->verifyFailedAircraftInfo(simObject, verifyMsg); // aircraft.cfg existing? + if (!verifyMsg.isEmpty()) { CLogMessage::preformatted(verifyMsg); } + + CSimConnectObject simObjAddAgain(simObject); + simObjAddAgain.increaseAddingExceptions(); + if (!simObject.hasCallsign()) + { + SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Missing callsign"); + return; + } + + if (!verifiedAircraft || simObjAddAgain.getAddingExceptions() > ThresholdAddException) + { + const CStatusMessage msg = + verifiedAircraft ? + CLogMessage(this).warning(u"Model '%1' %2 failed %3 time(s) before and will be disabled") + << simObjAddAgain.getAircraftModelString() << simObjAddAgain.toQString() + << simObjAddAgain.getAddingExceptions() : + CLogMessage(this).warning(u"Model '%1' %2 failed verification and will be disabled") + << simObjAddAgain.getAircraftModelString() << simObjAddAgain.toQString(); + this->updateAircraftEnabled(simObjAddAgain.getCallsign(), false); // disable + emit this->physicallyAddingRemoteModelFailed(simObjAddAgain.getAircraft(), true, true, + msg); // verify failed + } + else + { + CLogMessage(this).info(u"Will try '%1' again, aircraft: %2") + << simObject.getAircraftModelString() << simObject.getAircraft().toQString(true); + QPointer myself(this); + QTimer::singleShot(2000, this, [=] { + if (!myself) { return; } + if (this->isShuttingDownOrDisconnected()) { return; } + m_addPendingAircraft.insert(simObjAddAgain, true); // add failed object + }); + } + } + + bool CSimulatorMsfs2024::verifyFailedAircraftInfo(const CSimConnectObject &simObject, CStatusMessage &details) const + { + CAircraftModel model = simObject.getAircraftModel(); + + const CSpecializedSimulatorSettings settings = this->getSimulatorSettings(); + const bool fileExists = CFsCommonUtil::adjustFileDirectory(model, settings.getModelDirectoriesOrDefault()); + bool canBeUsed = true; + + CStatusMessageList messages; + if (fileExists) + { + // we can access the aircraft.cfg file + bool parsed = false; + const CAircraftCfgEntriesList entries = + CAircraftCfgParser::performParsingOfSingleFile(model.getFileName(), parsed, messages); + if (parsed) + { + if (entries.containsTitle(model.getModelString())) + { + messages.push_back(CStatusMessage(this).info(u"Model '%1' exists in re-parsed file '%2'.") + << model.getModelString() << model.getFileName()); + canBeUsed = true; // all OK + } + else + { + messages.push_back( + CStatusMessage(this).warning(u"Model '%1' no longer in re-parsed file '%2'. Models are: %3.") + << model.getModelString() << model.getFileName() << entries.getTitlesAsString(true)); + canBeUsed = false; // absolute no chance to use that one + } + } + else + { + messages.push_back(CStatusMessage(this).warning(u"CS: '%1' Cannot parse file: '%2' (existing: %3)") + << model.getCallsign().asString() << model.getFileName() + << boolToYesNo(model.hasExistingCorrespondingFile())); + } + } + else + { + // the file cannot be accessed right now, but the pilot client necessarily has access to them + // so we just carry on + messages = model.verifyModelData(); + } + + // as single message + details = messages.toSingleMessage(); + + // status + return canBeUsed; + } + + bool CSimulatorMsfs2024::logVerifyFailedAircraftInfo(const CSimConnectObject &simObject) const + { + CStatusMessage m; + const bool r = verifyFailedAircraftInfo(simObject, m); + if (!m.isEmpty()) { CLogMessage::preformatted(m); } + return r; + } + + void CSimulatorMsfs2024::verifyAddedTerrainProbe(const CSimulatedAircraft &remoteAircraftIn) + { + bool verified = false; + CCallsign cs; + + // no simObject reference outside that block, because it will be deleted + { + CSimConnectObject &simObject = m_simConnectObjects[remoteAircraftIn.getCallsign()]; + simObject.setConfirmedAdded(true); // terrain probe + simObject.resetTimestampToNow(); + cs = simObject.getCallsign(); + CLogMessage(this).info(u"Probe: '%1' '%2' confirmed, %3") + << simObject.getCallsignAsString() << simObject.getAircraftModelString() << simObject.toQString(); + + // fails for probe + // SIMCONNECT_DATA_REQUEST_ID requestId = this->obtainRequestIdForSimObjTerrainProbe(); + // verified = this->releaseAIControl(simObject, requestId); // release probe + verified = true; + } + + if (!verified) // cppcheck-suppress knownConditionTrueFalse + { + CLogMessage(this).info(u"Disable probes: '%1' failed to relase control") << cs.asString(); + m_useFsxTerrainProbe = false; + } + + // trigger new adding from pending if any + if (!m_addPendingAircraft.isEmpty()) { this->addPendingAircraftAfterAdded(); } + } + + void CSimulatorMsfs2024::timerBasedObjectAddOrRemove() + { + this->addPendingAircraft(AddByTimer); + if (!this->isTestMode()) { this->physicallyRemoveAircraftNotInProvider(); } + } + + void CSimulatorMsfs2024::addPendingAircraftAfterAdded() + { + this->addPendingAircraft(AddAfterAdded); // addPendingAircraft is already "non blocking" + } + + void CSimulatorMsfs2024::addPendingAircraft(AircraftAddMode mode) + { + if (m_addPendingAircraft.isEmpty()) { return; } + const CCallsignSet aircraftCallsignsInRange(this->getAircraftInRangeCallsigns()); + CSimulatedAircraftList toBeAddedAircraft; // aircraft still to be added + CCallsignSet toBeRemovedCallsigns; + + for (const CSimConnectObject &pendingSimObj : std::as_const(m_addPendingAircraft)) + { + SWIFT_VERIFY_X(pendingSimObj.hasCallsign(), Q_FUNC_INFO, "missing callsign"); + if (!pendingSimObj.hasCallsign()) { continue; } + if (pendingSimObj.isTerrainProbe() || aircraftCallsignsInRange.contains(pendingSimObj.getCallsign())) + { + toBeAddedAircraft.push_back(pendingSimObj.getAircraft()); + } + else { toBeRemovedCallsigns.push_back(pendingSimObj.getCallsign()); } + } + + // no longer required to be added + m_addPendingAircraft.removeCallsigns(toBeRemovedCallsigns); + m_addAgainAircraftWhenRemoved.removeByCallsigns(toBeRemovedCallsigns); + + // add aircraft, but "non blocking" + if (!toBeAddedAircraft.isEmpty()) + { + const CSimConnectObject oldestSimObject = m_addPendingAircraft.getOldestObject(); + const CSimulatedAircraft nextPendingAircraft = oldestSimObject.getAircraft(); + if (nextPendingAircraft.hasModelString()) + { + const QPointer myself(this); + QTimer::singleShot(100, this, [=] { + if (!myself) { return; } + if (this->isShuttingDownDisconnectedOrNoAircraft(nextPendingAircraft.isTerrainProbe())) { return; } + this->physicallyAddRemoteAircraftImpl(nextPendingAircraft, mode, oldestSimObject); + }); + } + else + { + CLogMessage(this).warning(u"Pending aircraft without model string will be removed"); + m_addPendingAircraft.removeByOtherSimObject(oldestSimObject); + } + } + } + + CSimConnectObject CSimulatorMsfs2024::removeFromAddPendingAndAddAgainAircraft(const CCallsign &callsign) + { + CSimConnectObject simObjectOld; + if (callsign.isEmpty()) { return simObjectOld; } + + m_addAgainAircraftWhenRemoved.removeByCallsign(callsign); + if (m_addPendingAircraft.contains(callsign)) + { + simObjectOld = m_addPendingAircraft[callsign]; + m_addPendingAircraft.remove(callsign); + } + return simObjectOld; + } + + bool CSimulatorMsfs2024::simulatorReportedObjectRemoved(DWORD objectID) + { + if (this->isShuttingDownOrDisconnected()) { return false; } + CSimConnectObject simObject = m_simConnectObjects.getSimObjectForObjectId(objectID); + if (!simObject.hasValidRequestAndObjectId()) { return false; } // object id from somewhere else + + const CCallsign callsign(simObject.getCallsign()); + Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign for removed object"); + + if (simObject.isPendingRemoved()) + { + // good case, object has been removed + // we can remove the simulator object + } + else + { + // object was removed, but removal was not requested by us + // this means we are out of the reality bubble or something else went wrong + // Possible reasons: + // 1) out of reality bubble, because we move to another airport or other reasons + // 2) wrong position (in ground etc.) + // 3) Simulator not running (ie in stopped mode) + CStatusMessage msg; + if (!simObject.getAircraftModelString().isEmpty() && + simObject.getAddingDirectlyRemoved() < ThresholdAddedAndDirectlyRemoved) + { + simObject.increaseAddingDirectlyRemoved(); + m_addPendingAircraft.insert(simObject, true); // insert removed objects and update ts + m_simConnectObjects.removeByOtherSimObject( + simObject); // we have it in pending now, no need to keep it in this list + + const CInterpolationAndRenderingSetupPerCallsign setup = + this->getInterpolationSetupPerCallsignOrDefault(callsign); + msg = CLogMessage(this).warning(u"Aircraft removed, '%1' '%2' object id '%3' out of reality bubble or " + u"other reason. Interpolator: '%4'") + << callsign.toQString() << simObject.getAircraftModelString() << objectID + << simObject.getInterpolatorInfo(setup.getInterpolatorMode()); + } + else if (simObject.getAddingDirectlyRemoved() < ThresholdAddedAndDirectlyRemoved) + { + const CStatusMessage m = + CLogMessage(this).warning( + u"Aircraft removed again multiple times and will be disabled, '%1' '%2' object id '%3'") + << callsign.toQString() << simObject.getAircraftModelString() << objectID; + this->updateAircraftEnabled(simObject.getCallsign(), false); + emit this->physicallyAddingRemoteModelFailed(simObject.getAircraft(), true, true, + m); // directly removed again + } + else + { + msg = CLogMessage(this).warning( + u"Removed '%1' from simulator, but was not initiated by us (swift): %1 '%2' object id %3") + << callsign.toQString() << simObject.getAircraftModelString() << objectID; + } + + // in all cases add verification details + this->logVerifyFailedAircraftInfo(simObject); + + // relay messages + if (!msg.isEmpty()) { emit this->driverMessages(msg); } + } + + // in all cases we remove the object + const int c = m_simConnectObjects.remove(callsign); + const bool removedAny = (c > 0); + const bool updated = this->updateAircraftRendered(simObject.getCallsign(), false); + if (updated) { emit this->aircraftRenderingChanged(simObject.getAircraft()); } + + // models we have to add again after removing + if (m_addAgainAircraftWhenRemoved.containsCallsign(callsign)) + { + const CSimulatedAircraft aircraftAddAgain = m_addAgainAircraftWhenRemoved.findFirstByCallsign(callsign); + m_addAgainAircraftWhenRemoved.removeByCallsign(callsign); + QPointer myself(this); + QTimer::singleShot(2500, this, [=] { + if (!myself) { return; } + if (this->isShuttingDownOrDisconnected()) { return; } + myself->physicallyAddRemoteAircraftImpl(aircraftAddAgain, AddedAfterRemoved); + }); + } + return removedAny; + } + + bool CSimulatorMsfs2024::setSimConnectObjectId(DWORD requestId, DWORD objectId) + { + return m_simConnectObjects.setSimConnectObjectIdForRequestId(requestId, objectId); + } + + bool CSimulatorMsfs2024::setCurrentLights(const CCallsign &callsign, const CAircraftLights &lights) + { + if (!m_simConnectObjects.contains(callsign)) { return false; } + m_simConnectObjects[callsign].setCurrentLightsInSimulator(lights); + return true; + } + + bool CSimulatorMsfs2024::setLightsAsSent(const CCallsign &callsign, const CAircraftLights &lights) + { + if (!m_simConnectObjects.contains(callsign)) { return false; } + m_simConnectObjects[callsign].setLightsAsSent(lights); + return true; + } + + void CSimulatorMsfs2024::timerEvent(QTimerEvent *event) + { + Q_UNUSED(event) + if (this->isShuttingDown()) { return; } + this->dispatch(); + } + + HRESULT CSimulatorMsfs2024::initEventsP3D() { return s_ok(); } + + bool CSimulatorMsfs2024::parseDetails(const CSimpleCommandParser &parser) + { + // .driver sendid on|off + if (parser.matchesPart(1, "sendid") && parser.hasPart(2)) + { + const bool trace = parser.toBool(2); + this->setTraceSendId(trace); + CLogMessage(this, CLogCategories::cmdLine()).info(u"Tracing %1 driver sendIds is '%2'") + << this->getSimulatorPluginInfo().getIdentifier() << boolToOnOff(trace); + return true; + } + + // .driver sboffsets on|off + if (parser.matchesPart(1, "sboffsets") && parser.hasPart(2)) + { + const bool on = parser.toBool(2); + this->setUsingSbOffsetValues(on); + CLogMessage(this, CLogCategories::cmdLine()).info(u"SB offsets is '%1'") << boolToOnOff(on); + return true; + } + + // .driver sblog on|off + if (parser.matchesPart(1, "sblog") && parser.hasPart(2)) + { + const bool on = parser.toBool(2); + m_logSbOffsets = on; + CLogMessage(this, CLogCategories::cmdLine()).info(u"SB log. offsets is '%1'") << boolToOnOff(on); + return true; + } + + return CSimulatorFsCommon::parseDetails(parser); + } + + void CSimulatorMsfs2024::registerHelp() + { + if (CSimpleCommandParser::registered( + "swift::simplugin::msfs2024common::CSimulatorMsfs2024::CSimulatorMsfs2024")) + { + return; + } + CSimpleCommandParser::registerCommand({ ".drv", "alias: .driver .plugin" }); + CSimpleCommandParser::registerCommand({ ".drv sendid on|off", "Trace simConnect sendId on|off" }); + CSimpleCommandParser::registerCommand({ ".drv sboffsets on|off", "SB offsets via simConnect on|off" }); + CSimpleCommandParser::registerCommand({ ".drv sblog on|off", "SB offsets logging on|off" }); + } + + CCallsign CSimulatorMsfs2024::getCallsignForPendingProbeRequests(DWORD requestId, bool remove) + { + const CCallsign cs = m_pendingProbeRequests.value(requestId); + if (remove) { m_pendingProbeRequests.remove(requestId); } + return cs; + } + + const QString &CSimulatorMsfs2024::modeToString(CSimulatorMsfs2024::AircraftAddMode mode) + { + static const QString e("external call"); + static const QString pt("add pending by timer"); + static const QString oa("add pending after object added"); + static const QString ar("add again after removed"); + static const QString dontKnow("???"); + + switch (mode) + { + case ExternalCall: return e; + case AddByTimer: return pt; + case AddAfterAdded: return oa; + case AddedAfterRemoved: return ar; + default: break; + } + return dontKnow; + } + + void CSimulatorMsfs2024::dispatch() + { + // call CSimulatorMsfs2024::SimConnectProc + Q_ASSERT_X(m_dispatchProc, Q_FUNC_INFO, "Missing DispatchProc"); + + // statistics + m_dispatchReceiveIdLast = SIMCONNECT_RECV_ID_NULL; + m_dispatchRequestIdLast = CSimConnectDefinitions::RequestEndMarker; + const qint64 start = QDateTime::currentMSecsSinceEpoch(); + + // process + const HRESULT hr = SimConnect_CallDispatch(m_hSimConnect, m_dispatchProc, this); + + // statistics + const qint64 end = QDateTime::currentMSecsSinceEpoch(); + m_dispatchTimeMs = end - start; + if (m_dispatchMaxTimeMs < m_dispatchTimeMs) + { + m_dispatchMaxTimeMs = m_dispatchTimeMs; + m_dispatchReceiveIdMaxTime = m_dispatchReceiveIdLast; + m_dispatchRequestIdMaxTime = m_dispatchRequestIdLast; + } + + // error handling + if (isFailure(hr)) + { + // on FSX we normally receive this one here when simulator goes down, and NOT onSimExit + // in that case sim status is Connected, but not PAUSED or SIMULATING + const SimulatorStatus simStatus = this->getSimulatorStatus(); + const bool disconnectedOrNotSimulating = + simStatus.testFlag(Disconnected) || !simStatus.testFlag(Simulating); + + m_dispatchErrors++; + this->triggerAutoTraceSendId(); + if (m_dispatchErrors == 2) + { + // 2nd time, an error / avoid multiple messages + // idea: if it happens once ignore + const QString msg = + QStringLiteral(u"%1: Dispatch error, sim.status: %2") + .arg(this->getSimulatorPluginInfo().getIdentifier(), ISimulator::statusToString(simStatus)); + CLogMessage(this).log( + disconnectedOrNotSimulating ? CStatusMessage::SeverityWarning : CStatusMessage::SeverityError, msg); + } + else if (m_dispatchErrors > 5) + { + // this normally happens during a FSX crash or shutdown with simconnect + const QString msg = + QStringLiteral(u"%1: Multiple dispatch errors, disconnecting. Sim.status: %2") + .arg(this->getSimulatorPluginInfo().getIdentifier(), ISimulator::statusToString(simStatus)); + CLogMessage(this).log( + disconnectedOrNotSimulating ? CStatusMessage::SeverityWarning : CStatusMessage::SeverityError, msg); + this->disconnectFrom(); + } + return; + } + m_dispatchErrors = 0; + } + + bool CSimulatorMsfs2024::physicallyAddRemoteAircraftImpl(const CSimulatedAircraft &newRemoteAircraft, + CSimulatorMsfs2024::AircraftAddMode addMode, + const CSimConnectObject &correspondingSimObject) + { + const CCallsign callsign(newRemoteAircraft.getCallsign()); + const bool probe = newRemoteAircraft.isTerrainProbe(); + + // entry checks + Q_ASSERT_X(CThreadUtils::isInThisThread(this), Q_FUNC_INFO, "thread"); + Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign"); + Q_ASSERT_X(newRemoteAircraft.hasModelString(), Q_FUNC_INFO, "missing model string"); + + // reset timer + m_simObjectTimer.start(AddPendingAircraftIntervalMs); // restart + + // remove outdated objects + const CSimConnectObjects outdatedAdded = + m_simConnectObjects.removeOutdatedPendingAdded(CSimConnectObject::AllTypes); + if (!outdatedAdded.isEmpty()) + { + const CCallsignSet callsigns = outdatedAdded.getAllCallsigns(false); + CLogMessage(this).warning(u"Removed %1 outdated object(s) pending for added: %2") + << outdatedAdded.size() << callsigns.getCallsignsAsString(true); + this->updateMultipleAircraftEnabled(callsigns, false); + + static const QString msgText("%1 outdated adding, %2"); + for (const CSimConnectObject &simObjOutdated : outdatedAdded) + { + const CStatusMessage msg = CStatusMessage(this).warning( + msgText.arg(simObjOutdated.getCallsign().asString(), simObjOutdated.toQString())); + emit this->physicallyAddingRemoteModelFailed(simObjOutdated.getAircraft(), true, true, + msg); // outdated + } + + // if this aircraft is also outdated, ignore + if (callsigns.contains(newRemoteAircraft.getCallsign())) { return false; } + } + + const bool hasPendingAdded = m_simConnectObjects.containsPendingAdded(); + bool canAdd = this->isSimulating() && !hasPendingAdded; + + Q_ASSERT_X(!hasPendingAdded || m_simConnectObjects.countPendingAdded() < 2, Q_FUNC_INFO, + "There must be only 0..1 pending objects"); + if (this->showDebugLogMessage()) + { + this->debugLogMessage(Q_FUNC_INFO, QStringLiteral("CS: '%1' mode: '%2' model: '%3'") + .arg(newRemoteAircraft.getCallsignAsString(), modeToString(addMode), + newRemoteAircraft.getModelString())); + this->debugLogMessage( + Q_FUNC_INFO, QStringLiteral("CS: '%1' pending callsigns: '%2', pending objects: '%3'") + .arg(newRemoteAircraft.getCallsignAsString(), + m_addPendingAircraft.getAllCallsignStrings(true).join(", "), + m_simConnectObjects.getPendingAddedCallsigns().getCallsignStrings().join(", "))); + } + + // do we need to remove/add again because something has changed? + // this handles changed model strings or an update of the model + if (m_simConnectObjects.contains(callsign)) + { + const CSimConnectObject simObject = m_simConnectObjects[callsign]; + const QString newModelString(newRemoteAircraft.getModelString()); + const QString simObjModelString(simObject.getAircraftModelString()); + const bool sameModel = + (simObjModelString == + newModelString); // compare on string only (other attributes might change such as mode) + + // same model, nothing will change, otherwise add again when removed + if (sameModel) + { + CLogMessage(this).info(u"CS: '%1' re-added same model '%2'") + << newRemoteAircraft.getCallsignAsString() << newModelString; + + // we restore rendered flag in case we are sure we are rendered + // this is used with rematching + const bool rendered = simObject.isConfirmedAdded() && simObject.isPending(); + if (rendered) { this->updateAircraftRendered(callsign, rendered); } + return true; + } + + this->physicallyRemoveRemoteAircraft(newRemoteAircraft.getCallsign()); + m_addAgainAircraftWhenRemoved.replaceOrAddByCallsign(newRemoteAircraft); + if (this->showDebugLogMessage()) + { + this->debugLogMessage(Q_FUNC_INFO, + QStringLiteral("CS: '%1' re-added changed model '%2', will be added again") + .arg(newRemoteAircraft.getCallsignAsString(), newModelString)); + } + return false; + } + + // situation check + CAircraftSituation situation(newRemoteAircraft.getSituation()); + if (canAdd && situation.isPositionOrAltitudeNull()) + { + // invalid position because position or altitude is null + const CAircraftSituationList situations(this->remoteAircraftSituations(callsign)); + if (situations.isEmpty()) + { + CLogMessage(this).warning(u"No valid situations for '%1', will be added as pending") + << callsign.asString(); + } + else + { + CLogMessage(this).warning(u"Invalid aircraft situation for new aircraft '%1', use closest situation") + << callsign.asString(); + situation = situations.findClosestTimeDistanceAdjusted(QDateTime::currentMSecsSinceEpoch()); + Q_ASSERT_X(!situation.isPositionOrAltitudeNull(), Q_FUNC_INFO, "Invalid situation for new aircraft"); + } + + // still invalid? + canAdd = situation.isPositionOrAltitudeNull(); + if (CBuildConfig::isLocalDeveloperDebugBuild()) + { + SWIFT_VERIFY_X(canAdd, Q_FUNC_INFO, "Expect valid situation"); + CLogMessage(this).warning(u"Invalid situation for '%1'") << callsign; + } + } + + // check if we can add, do not add if simulator is stopped or other objects pending + if (!canAdd) + { + CSimConnectObject &addPendingObj = m_addPendingAircraft[newRemoteAircraft.getCallsign()]; + addPendingObj.setAircraft(newRemoteAircraft); + addPendingObj.resetTimestampToNow(); + return false; + } + + // remove from pending and keep for later to remember fail counters + const CSimConnectObject removedPendingObj = this->removeFromAddPendingAndAddAgainAircraft(callsign); + + // create AI after crosschecking it + if (!probe && !this->isAircraftInRangeOrTestMode(callsign)) + { + CLogMessage(this).info(u"Skipping adding of '%1' since it is no longer in range") << callsign.asString(); + return false; + } + + // setup + const CInterpolationAndRenderingSetupPerCallsign setup = + this->getInterpolationSetupConsolidated(callsign, true); + const bool sendGround = setup.isSendingGndFlagToSimulator(); + + // FSX/P3D adding + bool adding = false; // will be added flag + const SIMCONNECT_DATA_REQUEST_ID requestId = + probe ? this->obtainRequestIdForSimObjTerrainProbe() : this->obtainRequestIdForSimObjAircraft(); + + // Initial situation, if possible from interpolation + CAircraftSituation initialSituation = newRemoteAircraft.getSituation(); // default + { + // Dummy CSimConnectObject just for interpolation + const CSimConnectObject dummyObject = CSimConnectObject( + newRemoteAircraft, 0, this, this, this->getRemoteAircraftProvider(), &m_interpolationLogger); + const CInterpolationResult result = + dummyObject.getInterpolation(QDateTime::currentMSecsSinceEpoch(), setup, 0); + if (result.getInterpolationStatus().isInterpolated()) + { + initialSituation = result.getInterpolatedSituation(); + } + } + + // TODO TZ handle underflow properly + CStatusMessage underflowStatus; + const SIMCONNECT_DATA_INITPOSITION initialPosition = + CSimulatorMsfs2024::aircraftSituationToFsxPosition(initialSituation, sendGround, true, &underflowStatus); + + QString modelString(newRemoteAircraft.getShortModelString()); + const QString modelLiveryString(newRemoteAircraft.getLiveryString()); + + if (this->showDebugLogMessage()) + { + this->debugLogMessage(Q_FUNC_INFO, + QStringLiteral("CS: '%1' model: '%2' livery: %3 request: %4, init pos: %5") + .arg(callsign.toQString(), modelString, modelLiveryString) + .arg(requestId) + .arg(fsxPositionToString(initialPosition))); + } + + const QByteArray modelStringBa = toFsxChar(modelString); + const QByteArray modelLiveryBa = toFsxChar(modelLiveryString); + + const QByteArray csBa = toFsxChar(callsign.toQString().left(12)); + CSimConnectObject::SimObjectType type = CSimConnectObject::AircraftNonAtc; + HRESULT hr = S_OK; + + if (probe) + { + hr = SimConnect_AICreateNonATCAircraft_EX1(m_hSimConnect, modelStringBa.constData(), + modelLiveryBa.constData(), csBa.constData(), initialPosition, + requestId); + + type = CSimConnectObject::TerrainProbe; + } + else + { + if (this->isAddingAsSimulatedObjectEnabled() && correspondingSimObject.hasCallsign() && + correspondingSimObject.getAddingExceptions() > 0 && + correspondingSimObject.getType() == CSimConnectObject::AircraftNonAtc) + { + CStatusMessage(this).warning( + u"Model '%1' for '%2' failed %1 time(s) before, using AICreateSimulatedObject now") + << newRemoteAircraft.getModelString() << callsign.toQString(); + + hr = SimConnect_AICreateNonATCAircraft_EX1(m_hSimConnect, modelStringBa.constData(), + modelLiveryBa.constData(), csBa.constData(), initialPosition, + requestId); + + type = CSimConnectObject::AircraftSimulatedObject; + } + else + { + hr = SimConnect_AICreateNonATCAircraft_EX1(m_hSimConnect, modelStringBa.constData(), + modelLiveryBa.constData(), csBa.constData(), initialPosition, + requestId); + + type = CSimConnectObject::AircraftNonAtc; + } + } + + if (!underflowStatus.isEmpty()) + { + CStatusMessage(this).warning(u"Underflow detecion for '%1', details '%2'") + << callsign.asString() << underflowStatus.getMessage(); + } + + if (isFailure(hr)) + { + const CStatusMessage msg = CStatusMessage(this).error(u"SimConnect, can not create AI traffic: '%1' '%2'") + << callsign.toQString() << modelString; + CLogMessage::preformatted(msg); + emit this->physicallyAddingRemoteModelFailed(newRemoteAircraft, true, true, msg); // SimConnect error + } + else + { + // we will request a new aircraft by request ID, later we will receive its object id + // so far this object id is 0 (DWORD) + const CSimConnectObject simObject = + this->insertNewSimConnectObject(newRemoteAircraft, requestId, type, removedPendingObj); + this->traceSendId(simObject, Q_FUNC_INFO, + QStringLiteral("mode: %1").arg(CSimulatorMsfs2024::modeToString(addMode)), true); + adding = true; + } + return adding; + } + + bool CSimulatorMsfs2024::physicallyAddAITerrainProbe(const ICoordinateGeodetic &coordinate, int number) + { + if (coordinate.isNull()) { return false; } + if (!this->isUsingFsxTerrainProbe()) { return false; } + Q_ASSERT_X(CThreadUtils::isInThisThread(this), Q_FUNC_INFO, "thread"); + + // static const QString modelString("OrcaWhale"); + // static const QString modelString("Water Drop"); // not working on P3Dx86/FSX, no requests on that id + // possible static const QString modelString("A321ACA"); static const QString + // modelString("AI_Tracker_Object_0"); static const QString modelString("Piper Cub"); // P3Dv86 works as + // nonATC/SimulatedObject static const QString modelString("Discovery Spaceshuttle"); // P3Dx86 works as + // nonATC/SimulatedObject + static const QString modelString("swiftTerrainProbe0"); + static const QString pseudoCallsign("PROBE%1"); // max 12 chars + static const CCountry ctry("SW", "SWIFT"); + static const CAirlineIcaoCode swiftAirline("SWI", "swift probe", ctry, "SWIFT", false, false); + static const CLivery swiftLivery(CLivery::getStandardCode(swiftAirline), swiftAirline, "swift probe"); + + const CCallsign cs(pseudoCallsign.arg(number)); + const CAircraftModel model(modelString, CAircraftModel::TypeTerrainProbe, QStringLiteral("swift terrain probe"), + CAircraftIcaoCode::unassignedIcao(), swiftLivery); + CAircraftSituation situation(cs, coordinate); + situation.setAltitude(terrainProbeAltitude()); + situation.setZeroPBH(); + const CSimulatedAircraft pseudoAircraft(cs, model, CUser("123456", "swift", cs), situation); + return this->physicallyAddRemoteAircraftImpl(pseudoAircraft, ExternalCall); + } + + int CSimulatorMsfs2024::physicallyInitAITerrainProbes(const ICoordinateGeodetic &coordinate, int number) + { + if (number < 1) { return 0; } + if (m_initFsxTerrainProbes) { return m_addedProbes; } + m_initFsxTerrainProbes = true; // no multiple inits + this->triggerAutoTraceSendId(); + + int c = 0; + for (int n = 0; n < number; ++n) + { + if (this->physicallyAddAITerrainProbe(coordinate, n)) { c++; } + } + + CLogMessage(this).info(u"Adding %1 FSX terrain probes") << number; + m_addedProbes = c; + return c; + } + + bool CSimulatorMsfs2024::physicallyRemoveRemoteAircraft(const CCallsign &callsign) + { + // only remove from sim + Q_ASSERT_X(CThreadUtils::isInThisThread(this), Q_FUNC_INFO, "wrong thread"); + if (callsign.isEmpty()) { return false; } // can happen if an object is not an aircraft + + // clean up anyway + this->removeFromAddPendingAndAddAgainAircraft(callsign); + + // really remove from simulator + if (!m_simConnectObjects.contains(callsign)) { return false; } // already fully removed or not yet added + CSimConnectObject &simObject = m_simConnectObjects[callsign]; + if (simObject.isPendingRemoved()) { return true; } + if (simObject.isTerrainProbe()) { return false; } + + // check for pending objects + m_addPendingAircraft.remove(callsign); // just in case still in list of pending aircraft + const bool pendingAdded = simObject.isPendingAdded(); // already added in simulator, but not yet confirmed + const bool stillWaitingForLights = !simObject.hasCurrentLightsInSimulator(); + if (!simObject.isRemovedWhileAdding() && (pendingAdded || stillWaitingForLights)) + { + // problem: we try to delete an aircraft just requested to be added + // best solution so far, call remove again with a delay + CLogMessage(this).warning(u"'%1' requested to be removed, but pending added (%2) / or pending lights(%3). " + u"Object will be removed again: %4") + << callsign.asString() << boolToYesNo(pendingAdded) << boolToYesNo(stillWaitingForLights) + << simObject.toQString(); + simObject.setRemovedWhileAdding(true); // next time kill + QPointer myself(this); + QTimer::singleShot(2000, this, [=] { + if (!myself) { return; } + CLogMessage(this).info(u"Next trial to remove '%1'") << callsign.asString(); + myself->physicallyRemoveRemoteAircraft(callsign); + }); + return false; // not yet deleted + } + + // no more data from simulator + this->stopRequestingDataForSimObject(simObject); + + // mark as removed + simObject.setPendingRemoved(true); + if (this->showDebugLogMessage()) + { + this->debugLogMessage(Q_FUNC_INFO, QStringLiteral("CS: '%1' request/object id: %2/%3") + .arg(callsign.toQString()) + .arg(simObject.getRequestId()) + .arg(simObject.getObjectId())); + } + + // call in SIM + const SIMCONNECT_DATA_REQUEST_ID requestId = simObject.getRequestId(CSimConnectDefinitions::SimObjectRemove); + this->removeCamera(simObject); + this->removeObserver(simObject); + const HRESULT result = SimConnect_AIRemoveObject( + m_hSimConnect, static_cast(simObject.getObjectId()), requestId); + if (isOk(result)) + { + if (this->isTracingSendId()) { this->traceSendId(simObject, Q_FUNC_INFO); } + } + else { CLogMessage(this).warning(u"Removing aircraft '%1' from simulator failed") << callsign.asString(); } + + // mark in provider + const bool updated = this->updateAircraftRendered(callsign, false); + if (updated) + { + CSimulatedAircraft aircraft(simObject.getAircraft()); + aircraft.setRendered(false); + emit this->aircraftRenderingChanged(aircraft); + } + + // cleanup function, actually this should not be needed + this->physicallyRemoveAircraftNotInProviderAsync(); + + // bye + return CSimulatorPluginCommon::physicallyRemoveRemoteAircraft(callsign); + } + + int CSimulatorMsfs2024::physicallyRemoveAllRemoteAircraft() + { + // make sure they are not added again + // cleaning here is somewhat redundant, but double checks + m_addPendingAircraft.clear(); + m_addAgainAircraftWhenRemoved.clear(); + + // remove one by one + int r = 0; + const CCallsignSet callsigns = m_simConnectObjects.getAllCallsigns(); + for (const CCallsign &cs : callsigns) + { + if (this->physicallyRemoveRemoteAircraft(cs)) { r++; } + } + + CSimulatorFsCommon::physicallyRemoveAllRemoteAircraft(); + return r; + } + + HRESULT CSimulatorMsfs2024::initEvents() + { + HRESULT hr = s_ok(); + // System events, see + // http://msdn.microsoft.com/en-us/library/cc526983.aspx#SimConnect_SubscribeToSystemEvent + hr += SimConnect_SubscribeToSystemEvent(m_hSimConnect, SystemEventSimStatus, "Sim"); + hr += SimConnect_SubscribeToSystemEvent(m_hSimConnect, SystemEventObjectAdded, "ObjectAdded"); + hr += SimConnect_SubscribeToSystemEvent(m_hSimConnect, SystemEventObjectRemoved, "ObjectRemoved"); + hr += SimConnect_SubscribeToSystemEvent(m_hSimConnect, SystemEventFrame, "Frame"); + hr += SimConnect_SubscribeToSystemEvent(m_hSimConnect, SystemEventPause, "Pause"); + hr += SimConnect_SubscribeToSystemEvent(m_hSimConnect, SystemEventFlightLoaded, "FlightLoaded"); + if (isFailure(hr)) + { + CLogMessage(this).error(u"FSX plugin error: %1") << "SimConnect_SubscribeToSystemEvent failed"; + return hr; + } + + // Mapped events, see event ids here: + // http://msdn.microsoft.com/en-us/library/cc526980.aspx + // http://www.prepar3d.com/SDKv2/LearningCenter/utilities/variables/event_ids.html + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventPauseToggle, "PAUSE_TOGGLE"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, SystemEventSlewToggle, "SLEW_TOGGLE"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventFreezeLatLng, + "FREEZE_LATITUDE_LONGITUDE_SET"); // FSX old standard + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventFreezeAlt, + "FREEZE_ALTITUDE_SET"); // FSX old standard + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventFreezeAtt, + "FREEZE_ATTITUDE_SET"); // FSX old standard + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetCom1Active, "COM_RADIO_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetCom1Standby, "COM_STBY_RADIO_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetCom2Active, "COM2_RADIO_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetCom2Standby, "COM2_STBY_RADIO_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetTransponderCode, "XPNDR_SET"); + + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetTimeZuluYear, "ZULU_YEAR_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetTimeZuluDay, "ZULU_DAY_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetTimeZuluHours, "ZULU_HOURS_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetTimeZuluMinutes, "ZULU_MINUTES_SET"); + + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandingLightsOff, "LANDING_LIGHTS_OFF"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandinglightsOn, "LANDING_LIGHTS_ON"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandingLightsSet, "LANDING_LIGHTS_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandingLightsToggle, "LANDING_LIGHTS_TOGGLE"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventPanelLightsOff, "PANEL_LIGHTS_OFF"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventPanelLightsOn, "PANEL_LIGHTS_ON"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventPanelLightsSet, "PANEL_LIGHTS_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesOff, "STROBES_OFF"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesOn, "STROBES_ON"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesSet, "STROBES_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesToggle, "STROBES_TOGGLE"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleBeaconLights, "TOGGLE_BEACON_LIGHTS"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleCabinLights, "TOGGLE_CABIN_LIGHTS"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleLogoLights, "TOGGLE_LOGO_LIGHTS"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleNavLights, "TOGGLE_NAV_LIGHTS"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleRecognitionLights, + "TOGGLE_RECOGNITION_LIGHTS"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleTaxiLights, "TOGGLE_TAXI_LIGHTS"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleWingLights, "TOGGLE_WING_LIGHTS"); + + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventFlapsSet, "FLAPS_SET"); + + if (isFailure(hr)) + { + CLogMessage(this).error(u"FSX plugin error: %1") << "SimConnect_MapClientEventToSimEvent failed"; + return hr; + } + + // facility + SIMCONNECT_DATA_REQUEST_ID requestId = + static_cast(CSimConnectDefinitions::RequestFacility); + hr += SimConnect_SubscribeToFacilities(m_hSimConnect, SIMCONNECT_FACILITY_LIST_TYPE_AIRPORT, requestId); + if (isFailure(hr)) + { + CLogMessage(this).error(u"FSX plugin error: %1") << "SimConnect_SubscribeToFacilities failed"; + return hr; + } + return hr; + } + + HRESULT CSimulatorMsfs2024::initDataDefinitionsWhenConnected() + { + + return CSimConnectDefinitions::initDataDefinitionsWhenConnected( + m_hSimConnect, this->getSimulatorPluginInfo().getSimulatorInfo()); + } + + HRESULT CSimulatorMsfs2024::initWhenConnected() + { + // called when connected + + HRESULT hr = this->initEvents(); + if (isFailure(hr)) + { + CLogMessage(this).error(u"FSX plugin: initEvents failed"); + return hr; + } + + // init data definitions and SB data area + hr += this->initDataDefinitionsWhenConnected(); + if (isFailure(hr)) + { + CLogMessage(this).error(u"FSX plugin: initDataDefinitionsWhenConnected failed"); + return hr; + } + + return hr; + } + + void CSimulatorMsfs2024::updateRemoteAircraft() + { + static_assert(sizeof(DataDefinitionRemoteAircraftPartsWithoutLights) == sizeof(double) * 10, + "DataDefinitionRemoteAircraftPartsWithoutLights has an incorrect size."); + Q_ASSERT_X(CThreadUtils::isInThisThread(this), Q_FUNC_INFO, "thread"); + + // nothing to do, reset request id and exit + const int remoteAircraftNo = this->getAircraftInRangeCount(); + if (remoteAircraftNo < 1) + { + m_statsUpdateAircraftRuns = 0; + return; + } + + // values used for position and parts + const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch(); + if (this->isUpdateAircraftLimitedWithStats(currentTimestamp)) + { + this->finishUpdateRemoteAircraftAndSetStatistics(currentTimestamp, true); + return; + } + m_updateRemoteAircraftInProgress = true; + + // interpolation for all remote aircraft + const QList simObjects(m_simConnectObjects.values()); + + uint32_t simObjectNumber = 0; + const bool traceSendId = this->isTracingSendId(); + const bool updateAllAircraft = this->isUpdateAllRemoteAircraft(currentTimestamp); + for (const CSimConnectObject &simObject : simObjects) + { + // happening if aircraft is not yet added to simulator or to be deleted + if (!simObject.isReadyToSend()) { continue; } + if (!simObject.hasCurrentLightsInSimulator()) { continue; } // wait until we have light state + + const CCallsign callsign(simObject.getCallsign()); + const bool hasCs = !callsign.isEmpty(); + const bool hasValidIds = simObject.hasValidRequestAndObjectId(); + SWIFT_VERIFY_X(hasCs, Q_FUNC_INFO, "missing callsign"); + SWIFT_AUDIT_X(hasValidIds, Q_FUNC_INFO, "Missing ids"); + if (!hasCs || !hasValidIds) { continue; } // not supposed to happen + const DWORD objectId = simObject.getObjectId(); + + // setup + const CInterpolationAndRenderingSetupPerCallsign setup = + this->getInterpolationSetupConsolidated(callsign, updateAllAircraft); + const bool sendGround = setup.isSendingGndFlagToSimulator(); + + // Interpolated situation + // simObjectNumber is passed to equally distributed steps like guessing parts + const bool slowUpdate = (((m_statsUpdateAircraftRuns + simObjectNumber) % 40) == 0); + const CInterpolationResult result = simObject.getInterpolation(currentTimestamp, setup, simObjectNumber++); + const bool forceUpdate = slowUpdate || updateAllAircraft || setup.isForcingFullInterpolation(); + if (result.getInterpolationStatus().hasValidSituation()) + { + // update situation + if (forceUpdate || !this->isEqualLastSent(result.getInterpolatedSituation())) + { + // adjust altitude to compensate for FS2020 temperature effect + CAircraftSituation situation = result; + const CLength relativeAltitude = + situation.geodeticHeight() - getOwnAircraftPosition().geodeticHeight(); + const double altitudeDeltaWeight = + 2 - qBound(3000.0, relativeAltitude.abs().value(CLengthUnit::ft()), 6000.0) / 3000; + situation.setAltitude({ situation.getAltitude() + m_altitudeDelta * altitudeDeltaWeight, + situation.getAltitude().getReferenceDatum() }); + + SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToFsxPosition(situation, sendGround); + const HRESULT hr = this->logAndTraceSendId( + SimConnect_SetDataOnSimObject(m_hSimConnect, + CSimConnectDefinitions::DataRemoteAircraftSetPosition, + static_cast(objectId), 0, 0, + sizeof(SIMCONNECT_DATA_INITPOSITION), &position), + traceSendId, simObject, "Failed to set position", Q_FUNC_INFO, "SimConnect_SetDataOnSimObject"); + if (isOk(hr)) + { + this->rememberLastSent(result); // remember situation + } + } + } + else + { + // already logged in interpolator + continue; + } + + // Interpolated parts + const bool updatedParts = this->updateRemoteAircraftParts(simObject, result, forceUpdate); + Q_UNUSED(updatedParts) + + } // all callsigns + + // stats + this->finishUpdateRemoteAircraftAndSetStatistics(currentTimestamp); + } + + bool CSimulatorMsfs2024::updateRemoteAircraftParts(const CSimConnectObject &simObject, + const CInterpolationResult &result, bool forcedUpdate) + { + if (!simObject.hasValidRequestAndObjectId()) { return false; } + if (!simObject.isConfirmedAdded()) { return false; } + + const CAircraftParts parts = result; + if (parts.isNull()) { return false; } + if (parts.getPartsDetails() != CAircraftParts::GuessedParts && !result.getPartsStatus().isSupportingParts()) + { + return false; + } + + const CCallsign cs = simObject.getCallsign(); + if (!forcedUpdate && (result.getPartsStatus().isReusedParts() || this->isEqualLastSent(parts, cs))) + { + return true; + } + + const bool ok = this->sendRemoteAircraftPartsToSimulator(simObject, parts); + if (ok) { this->rememberLastSent(parts, cs); } + return ok; + } + + // TODO TZ under investigation, flaps retracting to 0 again and other issues + bool CSimulatorMsfs2024::sendRemoteAircraftPartsToSimulator(const CSimConnectObject &simObject, + const CAircraftParts &parts) + { + Q_ASSERT(m_hSimConnect); + if (!simObject.isReadyToSend()) { return false; } + + const DWORD objectId = simObject.getObjectId(); + const bool traceId = this->isTracingSendId(); + + DataDefinitionRemoteAircraftPartsWithoutLights ddRemoteAircraftPartsWithoutLights(parts); + const CAircraftLights lights = parts.getAdjustedLights(); + + // in case we sent, we sent everything + const bool simObjectAircraftType = simObject.isAircraftSimulatedObject(); // no real aircraft type + const HRESULT hr1 = + simObjectAircraftType ? + S_OK : + this->logAndTraceSendId( + SimConnect_SetDataOnSimObject( + m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + static_cast(objectId), SIMCONNECT_DATA_SET_FLAG_DEFAULT, 0, + sizeof(DataDefinitionRemoteAircraftPartsWithoutLights), &ddRemoteAircraftPartsWithoutLights), + traceId, simObject, "Failed so set parts", Q_FUNC_INFO, + "SimConnect_SetDataOnSimObject::ddRemoteAircraftPartsWithoutLights"); + + // Sim variable version, not working, setting the value, but flaps retracting to 0 again + // Sets flap handle to closest increment (0 to 16383) + const DWORD flapsDw = static_cast(qMin(16383, qRound((parts.getFlapsPercent() / 100.0) * 16383))); + const HRESULT hr2 = this->logAndTraceSendId( + SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventFlapsSet, flapsDw, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed so set flaps", Q_FUNC_INFO, "SimConnect_TransmitClientEvent::EventFlapsSet"); + + // lights we can set directly + const HRESULT hr3 = this->logAndTraceSendId( + SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventLandingLightsSet, + lights.isLandingOn() ? 1.0 : 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed so set landing lights", Q_FUNC_INFO, + "SimConnect_TransmitClientEvent::EventLandingLightsSet"); + + const HRESULT hr4 = + this->logAndTraceSendId(SimConnect_TransmitClientEvent( + m_hSimConnect, objectId, EventStrobesSet, lights.isStrobeOn() ? 1.0 : 0.0, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed to set strobe lights", Q_FUNC_INFO, + "SimConnect_TransmitClientEvent::EventStrobesSet"); + + // lights we need to toggle + // (potential risk with quickly changing values that we accidentally toggle back, also we need the light + // state before we can toggle) + this->sendToggledLightsToSimulator(simObject, lights); + + // done + return isOk(hr1, hr2, hr3, hr4); + } + + bool CSimulatorMsfs2024::sendRemoteAircraftAtcDataToSimulator(const CSimConnectObject &simObject) + { + if (!simObject.isReadyToSend()) { return false; } + if (simObject.isTerrainProbe()) { return false; } + // if (simObject.getType() != CSimConnectObject::AircraftNonAtc) { return false; } // otherwise errors + + const DWORD objectId = simObject.getObjectId(); + const bool traceId = this->isTracingSendId(); + + DataDefinitionRemoteAtc ddAtc; + ddAtc.setDefaultValues(); + const QByteArray csBa = simObject.getCallsignByteArray(); + const QByteArray airlineBa = simObject.getAircraft().getAirlineIcaoCode().getName().toLatin1(); + const QByteArray flightNumberBa = QString::number(simObject.getObjectId()).toLatin1(); + + ddAtc.copyAtcId(csBa.constData()); + ddAtc.copyAtcAirline(airlineBa.constData()); + ddAtc.copyFlightNumber(flightNumberBa.constData()); + + // in case we sent, we sent everything + const HRESULT hr = this->logAndTraceSendId( + SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetData, + static_cast(objectId), SIMCONNECT_DATA_SET_FLAG_DEFAULT, + 0, sizeof(DataDefinitionRemoteAtc), &ddAtc), + traceId, simObject, "Failed so aircraft ATC data", Q_FUNC_INFO, "SimConnect_SetDataOnSimObject"); + // done + return isOk(hr); + } + + void CSimulatorMsfs2024::sendToggledLightsToSimulator(const CSimConnectObject &simObj, + const CAircraftLights &lightsWanted, bool force) + { + if (!simObj.isReadyToSend()) { return; } // stale + + const CAircraftLights lightsIsState = simObj.getCurrentLightsInSimulator(); + if (lightsWanted == lightsIsState) { return; } + if (!force && lightsWanted == simObj.getLightsAsSent()) { return; } + const CCallsign callsign(simObj.getCallsign()); + + // Update data + if (m_simConnectObjects.contains(callsign)) + { + CSimConnectObject &simObjToUpdate = m_simConnectObjects[callsign]; + simObjToUpdate.setLightsAsSent(lightsWanted); + } + + // state available, then I can toggle + if (!lightsIsState.isNull()) + { + const DWORD objectId = simObj.getObjectId(); + const bool trace = this->isTracingSendId(); + + if (lightsWanted.isTaxiOn() != lightsIsState.isTaxiOn()) + { + this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleTaxiLights, + 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + trace, simObj, "Toggle taxi lights", Q_FUNC_INFO, "EventToggleTaxiLights"); + } + if (lightsWanted.isNavOn() != lightsIsState.isNavOn()) + { + this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleNavLights, + 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + trace, simObj, "Toggle nav.lights", Q_FUNC_INFO, "EventToggleNavLights"); + } + if (lightsWanted.isBeaconOn() != lightsIsState.isBeaconOn()) + { + this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleBeaconLights, + 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + trace, simObj, "Toggle becon lights", Q_FUNC_INFO, "EventToggleBeaconLights"); + } + if (lightsWanted.isLogoOn() != lightsIsState.isLogoOn()) + { + this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleLogoLights, + 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + trace, simObj, "Toggle logo lights", Q_FUNC_INFO, "EventToggleLogoLights"); + } + if (lightsWanted.isRecognitionOn() != lightsIsState.isRecognitionOn()) + { + this->logAndTraceSendId( + SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleRecognitionLights, 0.0, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + trace, simObj, "Toggle recognition lights", Q_FUNC_INFO, "EventToggleRecognitionLights"); + } + if (lightsWanted.isCabinOn() != lightsIsState.isCabinOn()) + { + this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleCabinLights, + 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + trace, simObj, "Toggle cabin lights", Q_FUNC_INFO, "EventToggleCabinLights"); + } + return; + } + + // missing lights info from simulator so far + if (this->showDebugLogMessage()) + { + this->debugLogMessage(Q_FUNC_INFO, QStringLiteral("Missing light state in simulator for '%1', model '%2'") + .arg(callsign.asString(), simObj.getAircraftModelString())); + } + + const QPointer myself(this); + QTimer::singleShot(DeferResendingLights, this, [=] { + if (!myself) { return; } + if (!m_simConnectObjects.contains(callsign)) { return; } + const CSimConnectObject currentSimObject = m_simConnectObjects[callsign]; + if (!currentSimObject.isReadyToSend()) { return; } // stale + if (lightsWanted != currentSimObject.getLightsAsSent()) + { + return; + } // changed in between, so another call sendToggledLightsToSimulator is pending + if (this->showDebugLogMessage()) + { + this->debugLogMessage(Q_FUNC_INFO, QStringLiteral("Resending light state for '%1', model '%2'") + .arg(callsign.asString(), simObj.getAircraftModelString())); + } + this->sendToggledLightsToSimulator(currentSimObject, lightsWanted, true); + }); + } + + SIMCONNECT_DATA_INITPOSITION + CSimulatorMsfs2024::aircraftSituationToFsxPosition(const CAircraftSituation &situation, bool sendGnd, + bool forceUnderflowDetection, CStatusMessage *details) + { + Q_ASSERT_X(!situation.isGeodeticHeightNull(), Q_FUNC_INFO, "Missing height (altitude)"); + Q_ASSERT_X(!situation.isPositionNull(), Q_FUNC_INFO, "Missing position"); + + // lat/Lng, NO PBH + CAircraftSituation::AltitudeCorrection altCorrection = CAircraftSituation::UnknownCorrection; + SIMCONNECT_DATA_INITPOSITION position = CSimulatorMsfs2024::coordinateToFsxPosition(situation); + if (forceUnderflowDetection) + { + const CAltitude alt = situation.getCorrectedAltitude(true, &altCorrection); + position.Altitude = alt.value(CLengthUnit::ft()); + } + + // MSFS has inverted pitch and bank angles + position.Pitch = -situation.getPitch().value(CAngleUnit::deg()); + position.Bank = -situation.getBank().value(CAngleUnit::deg()); + position.Heading = situation.getHeading().value(CAngleUnit::deg()); + position.OnGround = 0U; // not on ground + + const double gsKts = situation.getGroundSpeed().value(CSpeedUnit::kts()); + position.Airspeed = static_cast(qRound(gsKts)); + + // sanity check + if (gsKts < 0.0) + { + // we get negative GS for pushback and helicopters + // here we handle them her with DWORD (unsigned) + position.Airspeed = 0U; + } + else { position.Airspeed = static_cast(qRound(gsKts)); } + + // send GND flag also when underflow detection is available + if ((sendGnd || forceUnderflowDetection) && situation.isOnGroundInfoAvailable()) + { + const bool onGround = situation.isOnGround(); + position.OnGround = onGround ? 1U : 0U; + } + + // if we have no GND flag yet (gnd flag prevents underflow) + if (forceUnderflowDetection && position.OnGround == 0 && + !CAircraftSituation::isCorrectedAltitude(altCorrection)) + { + // logical resolution failed so far, likely we have no CG or elevantion + // primitive guessing + do { + if (position.Airspeed < 2) + { + position.OnGround = 1U; + if (details) + { + *details = CStatusMessage(static_cast(nullptr)) + .warning(u"Force GND flag for underflow protection"); + } + break; + } + } + while (false); + } + + // crosscheck + if (CBuildConfig::isLocalDeveloperDebugBuild()) + { + SWIFT_VERIFY_X(isValidFsxPosition(position), Q_FUNC_INFO, "Invalid FSX pos."); + } + + return position; + } + + SIMCONNECT_DATA_PBH CSimulatorMsfs2024::aircraftSituationToFsxPBH(const CAircraftSituation &situation) + { + // MSFS has inverted pitch and bank angles + SIMCONNECT_DATA_PBH pbh; + pbh.Pitch = -situation.getPitch().value(CAngleUnit::deg()); + pbh.Bank = -situation.getBank().value(CAngleUnit::deg()); + pbh.Heading = situation.getHeading().value(CAngleUnit::deg()); + return pbh; + } + + SIMCONNECT_DATA_INITPOSITION + CSimulatorMsfs2024::coordinateToFsxPosition(const ICoordinateGeodetic &coordinate) + { + SIMCONNECT_DATA_INITPOSITION position; + position.Latitude = coordinate.latitude().value(CAngleUnit::deg()); + position.Longitude = coordinate.longitude().value(CAngleUnit::deg()); + position.Altitude = coordinate.geodeticHeight().value( + CLengthUnit::ft()); // already corrected in interpolator if there is an underflow + position.Heading = 0; + position.Airspeed = 0; + position.Pitch = 0; + position.Bank = 0; + position.OnGround = 0; + return position; + } + + SIMCONNECT_DATA_LATLONALT CSimulatorMsfs2024::coordinateToFsxLatLonAlt(const ICoordinateGeodetic &coordinate) + { + SIMCONNECT_DATA_LATLONALT lla; + lla.Latitude = coordinate.latitude().value(CAngleUnit::deg()); + lla.Longitude = coordinate.longitude().value(CAngleUnit::deg()); + lla.Altitude = coordinate.geodeticHeight().value( + CLengthUnit::ft()); // already corrected in interpolator if there is an underflow + return lla; + } + + bool CSimulatorMsfs2024::isValidFsxPosition(const SIMCONNECT_DATA_INITPOSITION &fsxPos) + { + // double Latitude; // degrees | double Longitude; // degrees | double Altitude; // feet + // double Pitch; // degrees | double Bank; // degrees | double Heading; // degrees + // DWORD OnGround; // 1=force to be on the ground | DWORD Airspeed; // knots + // https://www.prepar3d.com/SDKv4/sdk/simconnect_api/references/simobject_functions.html + // examples show heaading 180 => we assume values +-180deg + if (!isValid180Deg(fsxPos.Pitch)) { return false; } + if (!isValid180Deg(fsxPos.Bank)) { return false; } + if (!isValid180Deg(fsxPos.Heading)) { return false; } + if (!isValid180Deg(fsxPos.Latitude)) { return false; } + if (!isValid180Deg(fsxPos.Longitude)) { return false; } + return true; + } + + bool CSimulatorMsfs2024::requestPositionDataForSimObject(const CSimConnectObject &simObject, + SIMCONNECT_PERIOD period) + { + if (this->isShuttingDownOrDisconnected()) { return false; } + if (!simObject.hasValidRequestAndObjectId()) { return false; } + if (simObject.isPending()) { return false; } // wait until confirmed + if (simObject.getSimDataPeriod() == period) { return true; } // already queried like this + if (!m_simConnectObjects.contains(simObject.getCallsign())) { return false; } // removed in meantime + + // always request, not only when something has changed + const SIMCONNECT_DATA_REQUEST_ID reqId = static_cast( + simObject.getRequestId(CSimConnectDefinitions::SimObjectPositionData)); + const HRESULT result = this->logAndTraceSendId( + SimConnect_RequestDataOnSimObject(m_hSimConnect, reqId, + CSimConnectDefinitions::DataRemoteAircraftGetPosition, + simObject.getObjectId(), period), + simObject, "Cannot request simulator data", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); + + if (isOk(result)) + { + m_requestSimObjectDataCount++; + m_simConnectObjects[simObject.getCallsign()].setSimDataPeriod(period); + return true; + } + return false; + } + + bool CSimulatorMsfs2024::requestTerrainProbeData(const CSimConnectObject &simObject, + const CCallsign &aircraftCallsign) + { + static const QString w("Cannot request terrain probe data for id '%1'"); + const SIMCONNECT_DATA_REQUEST_ID requestId = + simObject.getRequestId(CSimConnectDefinitions::SimObjectPositionData); + const DWORD objectId = simObject.getObjectId(); + const HRESULT result = this->logAndTraceSendId( + SimConnect_RequestDataOnSimObject(m_hSimConnect, static_cast(requestId), + CSimConnectDefinitions::DataRemoteAircraftGetPosition, + static_cast(objectId), SIMCONNECT_PERIOD_ONCE), + simObject, w.arg(requestId), Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); + const bool ok = isOk(result); + if (ok) { m_pendingProbeRequests.insert(requestId, aircraftCallsign); } + return ok; + } + + bool CSimulatorMsfs2024::requestLightsForSimObject(const CSimConnectObject &simObject) + { + if (!this->isValidSimObjectNotPendingRemoved(simObject)) { return false; } + if (!m_hSimConnect) { return false; } + + // always request, not only when something has changed + const SIMCONNECT_DATA_REQUEST_ID requestId = simObject.getRequestId(CSimConnectDefinitions::SimObjectLights); + const HRESULT result = this->logAndTraceSendId( + SimConnect_RequestDataOnSimObject(m_hSimConnect, requestId, + CSimConnectDefinitions::DataRemoteAircraftLights, simObject.getObjectId(), + SIMCONNECT_PERIOD_SECOND), + simObject, "Cannot request lights data", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); + return isOk(result); + } + + bool CSimulatorMsfs2024::requestModelInfoForSimObject(const CSimConnectObject &simObject) + { + if (!this->isValidSimObjectNotPendingRemoved(simObject)) { return false; } + if (!m_hSimConnect) { return false; } + + // always request, not only when something has changed + const SIMCONNECT_DATA_REQUEST_ID requestId = simObject.getRequestId(CSimConnectDefinitions::SimObjectModel); + const HRESULT result = this->logAndTraceSendId( + SimConnect_RequestDataOnSimObject(m_hSimConnect, requestId, + CSimConnectDefinitions::DataRemoteAircraftModelData, + simObject.getObjectId(), SIMCONNECT_PERIOD_ONCE), + simObject, "Cannot request model info", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); + return isOk(result); + } + + bool CSimulatorMsfs2024::stopRequestingDataForSimObject(const CSimConnectObject &simObject) + { + if (!simObject.hasValidRequestAndObjectId()) { return false; } + if (!m_hSimConnect) { return false; } + + // stop by setting SIMCONNECT_PERIOD_NEVER + SIMCONNECT_DATA_REQUEST_ID requestId = simObject.getRequestId(CSimConnectDefinitions::SimObjectPositionData); + const HRESULT hr1 = this->logAndTraceSendId( + SimConnect_RequestDataOnSimObject(m_hSimConnect, requestId, + CSimConnectDefinitions::DataRemoteAircraftGetPosition, + simObject.getObjectId(), SIMCONNECT_PERIOD_NEVER), + simObject, "Stopping position request", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); + + requestId = simObject.getRequestId(CSimConnectDefinitions::SimObjectLights); + const HRESULT hr2 = this->logAndTraceSendId( + SimConnect_RequestDataOnSimObject(m_hSimConnect, requestId, + CSimConnectDefinitions::DataRemoteAircraftLights, simObject.getObjectId(), + SIMCONNECT_PERIOD_NEVER), + simObject, "Stopping lights request", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); + return isOk(hr1, hr2); + } + + void CSimulatorMsfs2024::initSimulatorInternals() + { + CSimulatorFsCommon::initSimulatorInternals(); + m_simulatorInternals.setValue("fsx/simConnectVersion", m_simConnectVersion); + } + + void CSimulatorMsfs2024::reset() + { + this->safeKillTimer(); + + // cleared below: + // physicallyRemoveAllRemoteAircraft + // m_simConnectObjects + // m_simConnectObjectsPositionAndPartsTraces + // m_addPendingAircraft + // m_updateRemoteAircraftInProgress + CSimulatorFsCommon::reset(); // clears all pending aircraft etc + + // reset values + m_simulatingChangedTs = -1; + m_simConnected = false; + m_simSimulating = false; + m_sbDataReceived = 0; + m_requestIdSimObjAircraft = static_cast(RequestSimObjAircraftStart); + m_dispatchErrors = 0; + m_receiveExceptionCount = 0; + m_addedProbes = 0; + m_initFsxTerrainProbes = false; + m_sendIdTraces.clear(); + } + + void CSimulatorMsfs2024::clearAllRemoteAircraftData() + { + const bool reinitProbe = + m_useFsxTerrainProbe && m_initFsxTerrainProbes; // re-init if enabled and was initialized + this->removeAllProbes(); + + // m_addAgainAircraftWhenRemoved cleared below + CSimulatorFsCommon::clearAllRemoteAircraftData(); // also removes aircraft + m_simConnectObjects.clear(); + m_addPendingAircraft.clear(); + m_simConnectObjectsPositionAndPartsTraces.clear(); + + if (reinitProbe) + { + // if we are still alive we re-init the probes + QPointer myself(this); + QTimer::singleShot(2000, this, [=] { + // Shutdown or unloaded + if (this->isShuttingDown() || !myself) { return; } + m_initFsxTerrainProbes = false; // probes will re-init + }); + } + } + + void CSimulatorMsfs2024::onOwnModelChanged(const CAircraftModel &newModel) + { + m_sbDataReceived = 0; + CSimulatorFsCommon::onOwnModelChanged(newModel); + } + + QString CSimulatorMsfs2024::fsxPositionToString(const SIMCONNECT_DATA_INITPOSITION &position) + { + static const QString positionStr( + "Lat: %1deg lng: %2deg alt: %3ft pitch: %4deg bank: %5deg hdg: %6deg airspeed: %7kts onGround: %8"); + return positionStr.arg(position.Latitude) + .arg(position.Longitude) + .arg(position.Altitude) + .arg(position.Pitch) + .arg(position.Bank) + .arg(position.Heading) + .arg(position.Airspeed) + .arg(position.OnGround); + } + + CCallsignSet CSimulatorMsfs2024::getCallsignsMissingInProvider() const + { + if (m_simConnectObjects.isEmpty()) { return CCallsignSet(); } + const CCallsignSet simObjectCallsigns(m_simConnectObjects.getAllCallsigns(true)); + const CCallsignSet providerCallsigns(this->getAircraftInRangeCallsigns()); + return simObjectCallsigns.difference(providerCallsigns); + } + + void CSimulatorMsfs2024::traceSendId(const CSimConnectObject &simObject, const QString &functionName, + const QString &details, bool forceTrace) + { + if (!forceTrace && !this->isTracingSendId()) { return; } + if (MaxSendIdTraces < 1) { return; } // cppcheck-suppress knownConditionTrueFalse + DWORD dwLastId = 0; + const HRESULT hr = SimConnect_GetLastSentPacketID(m_hSimConnect, &dwLastId); + if (isFailure(hr)) { return; } + if (m_sendIdTraces.size() > MaxSendIdTraces) { m_sendIdTraces.removeLast(); } + const TraceFsxSendId trace(dwLastId, simObject, + details.isEmpty() ? functionName : details % u", " % functionName); + m_sendIdTraces.push_front(trace); + } + + HRESULT CSimulatorMsfs2024::logAndTraceSendId(HRESULT hr, const QString &warningMsg, const QString &functionName, + const QString &functionDetails) + { + const CSimConnectObject empty; + return this->logAndTraceSendId(hr, empty, warningMsg, functionName, functionDetails); + } + + HRESULT CSimulatorMsfs2024::logAndTraceSendId(HRESULT hr, const CSimConnectObject &simObject, + const QString &warningMsg, const QString &functionName, + const QString &functionDetails) + { + return this->logAndTraceSendId(hr, this->isTracingSendId(), simObject, warningMsg, functionName, + functionDetails); + } + + HRESULT CSimulatorMsfs2024::logAndTraceSendId(HRESULT hr, bool traceSendId, const CSimConnectObject &simObject, + const QString &warningMsg, const QString &functionName, + const QString &functionDetails) + { + if (traceSendId) { this->traceSendId(simObject, functionName, functionDetails); } + if (isOk(hr)) { return hr; } + if (!warningMsg.isEmpty()) { CLogMessage(this).warning(warningMsg % u" SimObject: " % simObject.toQString()); } + this->triggerAutoTraceSendId(); + return hr; + } + + QByteArray CSimulatorMsfs2024::toFsxChar(const QString &string) { return string.toLatin1(); } + + TraceFsxSendId CSimulatorMsfs2024::getSendIdTrace(DWORD sendId) const + { + for (const TraceFsxSendId &trace : m_sendIdTraces) + { + if (trace.sendId == sendId) { return trace; } + } + return TraceFsxSendId::invalid(); + } + + QString CSimulatorMsfs2024::getSendIdTraceDetails(DWORD sendId) const + { + const TraceFsxSendId trace = this->getSendIdTrace(sendId); + if (trace.sendId == sendId) { return this->getSendIdTraceDetails(trace); } + return {}; + } + + QString CSimulatorMsfs2024::getSendIdTraceDetails(const TraceFsxSendId &trace) const + { + static const QString d("Send id: %1 obj.id.: %2 SimObj: %3 | '%4'"); + if (trace.isInvalid()) { return QString(); } + + // update with latest sim object + const CSimConnectObject simObject = this->getSimObjectForTrace(trace); + return d.arg(trace.sendId).arg(simObject.getObjectId()).arg(simObject.toQString(), trace.comment); + } + + int CSimulatorMsfs2024::removeAllProbes() + { + if (!m_hSimConnect) { return 0; } // already disconnected + const QList probes = m_simConnectObjects.getProbes(); + + int c = 0; + for (const CSimConnectObject &probeSimObject : probes) + { + if (!probeSimObject.isConfirmedAdded()) { continue; } + const SIMCONNECT_DATA_REQUEST_ID requestId = + probeSimObject.getRequestId(CSimConnectDefinitions::SimObjectRemove); + const HRESULT result = SimConnect_AIRemoveObject( + m_hSimConnect, static_cast(probeSimObject.getObjectId()), requestId); + if (isOk(result)) { c++; } + else + { + CLogMessage(this).warning(u"Removing probe '%1' from simulator failed") << probeSimObject.getObjectId(); + } + } + m_simConnectObjects.removeAllProbes(); + m_pendingProbeRequests.clear(); + return c; + } + + CSimConnectObject CSimulatorMsfs2024::insertNewSimConnectObject(const CSimulatedAircraft &aircraft, DWORD requestId, + CSimConnectObject::SimObjectType type, + const CSimConnectObject &removedPendingObject) + { + if (m_simConnectObjects.contains(aircraft.getCallsign())) + { + // error, ...? + CSimConnectObject &simObject = m_simConnectObjects[aircraft.getCallsign()]; + simObject.copyAddingFailureCounters(removedPendingObject); + simObject.resetTimestampToNow(); + return simObject; + } + + CSimConnectObject simObject; + if (m_simConnectObjectsPositionAndPartsTraces.contains(aircraft.getCallsign())) + { + // if in traces, get the object and reuse it + simObject = m_simConnectObjectsPositionAndPartsTraces[aircraft.getCallsign()]; + m_simConnectObjectsPositionAndPartsTraces.remove(aircraft.getCallsign()); + simObject.resetState(); + simObject.setRequestId(requestId); + simObject.setAircraft(aircraft); + simObject.attachInterpolatorLogger(&m_interpolationLogger); // setting a logger does not start logging + } + else + { + simObject = CSimConnectObject(aircraft, requestId, this, this, this->getRemoteAircraftProvider(), + &m_interpolationLogger); + } + simObject.copyAddingFailureCounters(removedPendingObject); + simObject.setType(type); + m_simConnectObjects.insert(simObject, true); // update timestamp + return simObject; + } + + const CAltitude &CSimulatorMsfs2024::terrainProbeAltitude() + { + static const CAltitude alt(50000, CLengthUnit::ft()); + return alt; + } + + QString CSimulatorMsfs2024::fsxCharToQString(const char *fsxChar, int size) + { + return QString::fromLatin1(fsxChar, size); + } + + QString CSimulatorMsfs2024::requestIdToString(DWORD requestId) + { + if (requestId <= CSimConnectDefinitions::RequestEndMarker) + { + return CSimConnectDefinitions::requestToString(static_cast(requestId)); + } + + const CSimConnectDefinitions::SimObjectRequest simRequest = requestToSimObjectRequest(requestId); + const CSimConnectObject::SimObjectType simType = CSimConnectObject::requestIdToType(requestId); + + static const QString req("%1 %2 %3"); + return req.arg(requestId) + .arg(CSimConnectObject::typeToString(simType)) + .arg(CSimConnectDefinitions::simObjectRequestToString(simRequest)); + } + + DWORD CSimulatorMsfs2024::unitTestRequestId(CSimConnectObject::SimObjectType type) + { + int start; + int end; + switch (type) + { + case CSimConnectObject::TerrainProbe: + start = RequestSimObjTerrainProbeStart; + end = RequestSimObjTerrainProbeEnd; + break; + case CSimConnectObject::AircraftNonAtc: + case CSimConnectObject::AircraftSimulatedObject: + default: + start = RequestSimObjAircraftStart; + end = RequestSimObjAircraftEnd; + break; + } + + const int id = CMathUtils::randomInteger(start, end); + return static_cast(id); + } + + CCallsignSet CSimulatorMsfs2024::physicallyRemoveAircraftNotInProvider() + { + const CCallsignSet callsignsToBeRemoved(this->getCallsignsMissingInProvider()); + if (callsignsToBeRemoved.isEmpty()) { return callsignsToBeRemoved; } + for (const CCallsign &callsign : callsignsToBeRemoved) { this->physicallyRemoveRemoteAircraft(callsign); } + + if (this->showDebugLogMessage()) + { + this->debugLogMessage(Q_FUNC_INFO, + QStringLiteral("CS: '%1'").arg(callsignsToBeRemoved.toStringList().join(", "))); + } + return callsignsToBeRemoved; + } + + void CSimulatorMsfs2024::physicallyRemoveAircraftNotInProviderAsync() + { + const QPointer myself(this); + QTimer::singleShot(100, this, [=] { + if (!myself || this->isShuttingDown()) { return; } + CSimulatorMsfs2024::physicallyRemoveAircraftNotInProvider(); + }); + } + + CSimulatorMsfs2024Listener::CSimulatorMsfs2024Listener(const CSimulatorPluginInfo &info) : ISimulatorListener(info) + { + m_timer.setInterval(MinQueryIntervalMs); + m_timer.setObjectName(this->objectName().append(":m_timer")); + connect(&m_timer, &QTimer::timeout, this, &CSimulatorMsfs2024Listener::checkConnection); + } + + void CSimulatorMsfs2024Listener::startImpl() + { + m_simulatorVersion.clear(); + m_simConnectVersion.clear(); + m_simulatorName.clear(); + m_simulatorDetails.clear(); + + m_timer.start(); + } + + void CSimulatorMsfs2024Listener::stopImpl() + { + m_timer.stop(); + this->disconnectFromSimulator(); + } + + void CSimulatorMsfs2024Listener::checkImpl() + { + if (!m_timer.isActive()) { return; } + if (this->isShuttingDown()) { return; } + + QPointer myself(this); + QTimer::singleShot(0, this, [=] { + if (!myself || !sApp || sApp->isShuttingDown()) { return; } + this->checkConnection(); + }); + + // restart because we have just checked now + m_timer.start(); + } + + QString CSimulatorMsfs2024Listener::backendInfo() const + { + if (m_simulatorName.isEmpty()) { return ISimulatorListener::backendInfo(); } + return m_simulatorDetails; + } + + void CSimulatorMsfs2024Listener::checkConnection() + { + Q_ASSERT_X(!CThreadUtils::thisIsMainThread(), Q_FUNC_INFO, "Expect to run in background"); + + // check before we access the sim. connection + if (this->isShuttingDown() || this->thread()->isInterruptionRequested()) + { + this->stopImpl(); + return; + } + + QElapsedTimer t; + t.start(); + bool check = false; + do { + // if we can connect, but not dispatch, it can mean a previously started FSX/P3D + // blocks remote calls -> RESTART + if (!this->connectToSimulator()) { break; } + + // check if we have the right sim. + // this check on a remote FSX/P3D not running/existing might TAKE LONG! + const HRESULT result = + SimConnect_CallDispatch(m_hSimConnect, CSimulatorMsfs2024Listener::SimConnectProc, this); + + // make sure we did not stop in meantime + if (this->isShuttingDown() || this->thread()->isInterruptionRequested()) + { + this->stopImpl(); + return; + } + + if (isFailure(result)) { break; } // means serious failure + check = this->checkVersionAndSimulator(); + } + while (false); + + this->adjustTimerInterval(t.elapsed()); + if (check) { emit this->simulatorStarted(this->getPluginInfo()); } + } + + void CSimulatorMsfs2024Listener::adjustTimerInterval(qint64 checkTimeMs) + { + const QString sim = this->getPluginInfo().getSimulatorInfo().toQString(true); + CLogMessage(this).debug(u"Checked sim.'%1' connection in %2ms") << sim << checkTimeMs; + if (checkTimeMs > qRound(1.25 * MinQueryIntervalMs)) + { + const int newIntervalMs = qRound(1.2 * checkTimeMs / 1000.0) * 1000; + CLogMessage(this).debug(u"Check for simulator sim.'%1' connection in %2ms, too slow. Setting %3ms") + << sim << checkTimeMs << newIntervalMs; + if (m_timer.interval() != newIntervalMs) { m_timer.setInterval(newIntervalMs); } + } + else + { + if (m_timer.interval() != MinQueryIntervalMs) { m_timer.setInterval(MinQueryIntervalMs); } + } + + // restart + m_timer.start(); + } + + bool CSimulatorMsfs2024Listener::checkVersionAndSimulator() const + { + const CSimulatorInfo pluginSim(getPluginInfo().getIdentifier()); + const QString connectedSimName = m_simulatorName.toLower().trimmed(); + + if (connectedSimName.isEmpty()) { return false; } + if (pluginSim.isP3D()) + { + // P3D drivers only works with P3D + return connectedSimName.contains("lockheed") || connectedSimName.contains("martin") || + connectedSimName.contains("p3d") || connectedSimName.contains("prepar"); + } + else if (pluginSim.isFSX()) + { + // FSX drivers only works with FSX + 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; + } + + bool CSimulatorMsfs2024Listener::checkSimConnectDll() const + { + static const CWinDllUtils::DLLInfo simConnectInfo = CSimConnectUtilities::simConnectDllInfo(); + if (!simConnectInfo.errorMsg.isEmpty()) { return false; } + return true; + } + + bool CSimulatorMsfs2024Listener::connectToSimulator() + { + if (m_simConnected) { return true; } + const HRESULT result = SimConnect_Open(&m_hSimConnect, sApp->swiftVersionChar(), nullptr, 0, nullptr, 0); + const bool ok = isOk(result); + m_simConnected = ok; + return ok; + } + + bool CSimulatorMsfs2024Listener::disconnectFromSimulator() + { + if (!m_simConnected) { return false; } + SimConnect_Close(m_hSimConnect); + m_hSimConnect = nullptr; + m_simConnected = false; + return true; + } + + void CSimulatorMsfs2024Listener::SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext) + { + Q_UNUSED(cbData) + CSimulatorMsfs2024Listener *simListener = static_cast(pContext); + switch (pData->dwID) + { + case SIMCONNECT_RECV_ID_OPEN: + { + SIMCONNECT_RECV_OPEN *event = static_cast(pData); + simListener->m_simulatorVersion = QStringLiteral("%1.%2.%3.%4") + .arg(event->dwApplicationVersionMajor) + .arg(event->dwApplicationVersionMinor) + .arg(event->dwApplicationBuildMajor) + .arg(event->dwApplicationBuildMinor); + simListener->m_simConnectVersion = QStringLiteral("%1.%2.%3.%4") + .arg(event->dwSimConnectVersionMajor) + .arg(event->dwSimConnectVersionMinor) + .arg(event->dwSimConnectBuildMajor) + .arg(event->dwSimConnectBuildMinor); + simListener->m_simulatorName = CSimulatorMsfs2024::fsxCharToQString(event->szApplicationName); + simListener->m_simulatorDetails = QStringLiteral("Name: '%1' Version: %2 SimConnect: %3") + .arg(simListener->m_simulatorName, simListener->m_simulatorVersion, + simListener->m_simConnectVersion); + const CStatusMessage msg = CStatusMessage(simListener).info(u"Connect to %1: '%2'") + << simListener->getPluginInfo().getIdentifier() << simListener->backendInfo(); + + // avoid the same message over and over again + if (msg.getMessage() != simListener->m_lastMessage.getMessage()) + { + CLogMessage::preformatted(msg); + simListener->m_lastMessage = msg; + } + break; + } + case SIMCONNECT_RECV_ID_EXCEPTION: break; + default: break; + } + } +} // namespace swift::simplugin::msfs2024common diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.h b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h new file mode 100644 index 0000000000..464d2485ac --- /dev/null +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h @@ -0,0 +1,817 @@ +// 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/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, + EventToggleBeaconLights, + EventToggleCabinLights, + EventToggleLogoLights, + EventToggleNavLights, + EventToggleRecognitionLights, + EventToggleTaxiLights, + EventToggleWingLights, + // ------------- flaps ------------- + EventFlapsSet, + // ---------- 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 probe + bool isForProbe() const { return simObject.getType() == CSimConnectObject::TerrainProbe; } + + //! 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); + + //! FSX Terrain probe + //! \remark must be off at P3D v4.2 drivers or later + bool isUsingFsxTerrainProbe() const { return m_useFsxTerrainProbe; } + + //! FSX terrain probe + void setUsingFsxTerrainProbe(bool use) { m_useFsxTerrainProbe = use; } + + //! 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 probe (elevation)? + static bool isRequestForSimObjTerrainProbe(DWORD requestId) + { + return requestId >= RequestSimObjTerrainProbeStart && requestId <= RequestSimObjTerrainProbeRangeEnd; + } + + //! Request for any CSimConnectObject? + static bool isRequestForSimConnectObject(DWORD requestId) + { + return isRequestForSimObjAircraft(requestId) || isRequestForSimObjTerrainProbe(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(); + + //! Get new request id, overflow safe + SIMCONNECT_DATA_REQUEST_ID obtainRequestIdForSimObjTerrainProbe(); + + //! 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 + aircraftSituationToFsxPosition(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 + + // probes + bool m_useFsxTerrainProbe = is32bit(); //!< Use FSX Terrain probe? + bool m_initFsxTerrainProbes = false; //!< initialized terrain probes + int m_addedProbes = 0; //!< added probes + 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 = {}); + + //! Add AI object for terrain probe + //! \remark experimental + bool physicallyAddAITerrainProbe(const swift::misc::geo::ICoordinateGeodetic &coordinate, int number); + + //! Add number probes (inits the probe objects) + //! \remark experimental + int physicallyInitAITerrainProbes(const swift::misc::geo::ICoordinateGeodetic &coordinate, int number); + + //! 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; + + //! Verify the probe + void verifyAddedTerrainProbe(const swift::misc::simulation::CSimulatedAircraft &remoteAircraftIn); + + //! 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); + + //! Send lights to simulator (those which have to be toggled) + //! \remark challenge here is that I can only sent those value if I have already obtained the current light + //! state from simulator \param force send lights even if they appear to be the same + void sendToggledLightsToSimulator(const CSimConnectObject &simObject, + const swift::misc::aviation::CAircraftLights &lightsWanted, + bool force = false); + + //! 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 updateMSFSTransponderMode(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 data for the terrain probe + bool requestTerrainProbeData(const CSimConnectObject &simObject, + const swift::misc::aviation::CCallsign &aircraftCallsign); + + //! 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; + + // -- range for probe data, each probe object will get its own request id and use the offset ranges + static constexpr int RequestSimObjTerrainProbeStart = RequestSimObjAircraftRangeEnd + 1; + static constexpr int RequestSimObjTerrainProbeEnd = RequestSimObjTerrainProbeStart - 1 + MaxSimObjProbes; + static constexpr int RequestSimObjTerrainProbeRangeEnd = + RequestSimObjTerrainProbeStart - 1 + + static_cast(CSimConnectDefinitions::SimObjectEndMarker) * MaxSimObjProbes; + + // times + static constexpr int AddPendingAircraftIntervalMs = 20 * 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 + SIMCONNECT_DATA_REQUEST_ID m_requestIdSimObjTerrainProbe = static_cast( + RequestSimObjTerrainProbeStart); //!< request id, use obtainRequestIdForSimObjTerrainProbe 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; + + public: + //! @{ + //! Offsets + static DWORD offsetSimObjAircraft(CSimConnectDefinitions::SimObjectRequest req) + { + return MaxSimObjAircraft * static_cast(req); + } + static DWORD offsetSimObjTerrainProbe(CSimConnectDefinitions::SimObjectRequest req) + { + return MaxSimObjProbes * 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 diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp new file mode 100644 index 0000000000..4517b2d031 --- /dev/null +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp @@ -0,0 +1,464 @@ +// SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +#include + +#include + +#include "simconnectdatadefinitionmsfs2024.h" +#include "simulatormsfs2024common.h" + +#include "config/buildconfig.h" +#include "core/application.h" +#include "core/simulator.h" +#include "misc/aviation/airportlist.h" +#include "misc/logmessage.h" +#include "misc/simulation/fscommon/bcdconversions.h" +#include "misc/simulation/fsx/simconnectutilities.h" +#include "misc/simulation/settings/simulatorsettings.h" +#include "misc/simulation/simulatorplugininfo.h" + +using namespace swift::core; +using namespace swift::config; +using namespace swift::misc; +using namespace swift::misc::simulation; +using namespace swift::misc::aviation; +using namespace swift::misc::physical_quantities; +using namespace swift::misc::geo; +using namespace swift::misc::network; +using namespace swift::misc::simulation; +using namespace swift::misc::simulation::fscommon; +using namespace swift::misc::simulation::fsx; +using namespace swift::misc::simulation::settings; + +namespace swift::simplugin::msfs2024common +{ + void CALLBACK CSimulatorMsfs2024::SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext) + { + // IMPORTANT: + // all tasks called in this function (ie all called functions) must perform fast or shall be called + // asynchronously + + const qint64 procTimeStart = QDateTime::currentMSecsSinceEpoch(); + CSimulatorMsfs2024 *simulatorMsfs2024 = static_cast(pContext); + const SIMCONNECT_RECV_ID recvId = static_cast(pData->dwID); + static const DataDefinitionOwnAircraftModel *dataDefinitionModel; + simulatorMsfs2024->m_dispatchReceiveIdLast = recvId; + simulatorMsfs2024->m_dispatchProcCount++; + const CSpecializedSimulatorSettings settings = simulatorMsfs2024->getSimulatorSettings(); + CSimulatorSettings m_generic = settings.getGenericSettings(); + + switch (recvId) + { + case SIMCONNECT_RECV_ID_OPEN: + { + SIMCONNECT_RECV_OPEN *event = static_cast(pData); + const QString simConnectVersion = QStringLiteral("%1.%2.%3.%4") + .arg(event->dwSimConnectVersionMajor) + .arg(event->dwSimConnectVersionMinor) + .arg(event->dwSimConnectBuildMajor) + .arg(event->dwSimConnectBuildMinor); + const QString version = QStringLiteral("%1.%2.%3.%4") + .arg(event->dwApplicationVersionMajor) + .arg(event->dwApplicationVersionMinor) + .arg(event->dwApplicationBuildMajor) + .arg(event->dwApplicationBuildMinor); + const QString name = CSimulatorMsfs2024::fsxCharToQString(event->szApplicationName); + const QString details = + QStringLiteral("Name: '%1' Version: %2 SimConnect: %3").arg(name, version, simConnectVersion); + simulatorMsfs2024->setSimulatorDetails(name, details, version); + simulatorMsfs2024->m_simConnectVersion = simConnectVersion; + CLogMessage(simulatorMsfs2024).info(u"Connected to %1: '%2'") + << simulatorMsfs2024->getSimulatorPluginInfo().getIdentifier() << details; + simulatorMsfs2024->setSimConnected(); + break; // SIMCONNECT_RECV_ID_OPEN + } + case SIMCONNECT_RECV_ID_EXCEPTION: + { + if (!simulatorMsfs2024->stillDisplayReceiveExceptions()) { break; } + simulatorMsfs2024->triggerAutoTraceSendId(); + + SIMCONNECT_RECV_EXCEPTION *exception = static_cast(pData); + const DWORD exceptionId = exception->dwException; + const DWORD sendId = exception->dwSendID; + const DWORD index = exception->dwIndex; // index of parameter that was source of error, + // 4294967295/0xFFFFFFFF means unknown, 0 means also UNKNOWN INDEX + const DWORD data = cbData; + const TraceFsxSendId trace = simulatorMsfs2024->getSendIdTrace(sendId); + bool logGenericExceptionInfo = true; + + switch (exceptionId) + { + case SIMCONNECT_EXCEPTION_OPERATION_INVALID_FOR_OBJECT_TYPE: break; + case SIMCONNECT_EXCEPTION_UNRECOGNIZED_ID: + break; // Specifies that the client event, request ID, data definition ID, or object ID was not + // recognized + case SIMCONNECT_EXCEPTION_CREATE_OBJECT_FAILED: + { + if (trace.isValid()) + { + // it can happen the object is not yet existing + CSimConnectObject simObject = simulatorMsfs2024->getSimObjectForTrace(trace); + if (simObject.isInvalid()) { simObject = trace.simObject; } // take the one in the trace + if (simObject.isValid()) + { + if (simObject.isAircraft()) + { + simulatorMsfs2024->addingAircraftFailed(simObject); + logGenericExceptionInfo = false; + } + else + { + const bool removed = simulatorMsfs2024->m_simConnectObjects.remove(simObject.getCallsign()); + Q_UNUSED(removed); + CLogMessage(simulatorMsfs2024).warning(u"Adding probe failed: %1 %2") + << simObject.getCallsign().asString() << simObject.getAircraftModelString(); + if (simulatorMsfs2024->isUsingFsxTerrainProbe()) + { + CLogMessage(simulatorMsfs2024).warning(u"Disabling terrain probe"); + simulatorMsfs2024->setUsingFsxTerrainProbe(false); + } + logGenericExceptionInfo = false; + } // aircraft + } // valid + } // trace + } // SIMCONNECT_EXCEPTION_CREATE_OBJECT_FAILED: + break; + default: break; + } // switch exception id + + // generic exception warning + if (logGenericExceptionInfo) + { + QString ex = QString::asprintf("Exception=%lu | SendID=%lu | Index=%lu | cbData=%lu", exceptionId, + sendId, index, data); + const QString exceptionString( + CSimConnectUtilities::simConnectExceptionToString(static_cast(exception->dwException))); + const QString sendIdDetails = simulatorMsfs2024->getSendIdTraceDetails(sendId); + CLogMessage(simulatorMsfs2024).warning(u"Caught simConnect exception: '%1' '%2' | send details: '%3'") + << exceptionString << ex << (sendIdDetails.isEmpty() ? "N/A" : sendIdDetails); + } + break; // SIMCONNECT_RECV_ID_EXCEPTION + } + case SIMCONNECT_RECV_ID_QUIT: + { + simulatorMsfs2024->onSimExit(); + break; + } + case SIMCONNECT_RECV_ID_EVENT: + { + const SIMCONNECT_RECV_EVENT *event = static_cast(pData); + switch (event->uEventID) + { + case SystemEventSimStatus: + { + const bool running = event->dwData ? true : false; + if (running) { simulatorMsfs2024->onSimRunning(); } + else { simulatorMsfs2024->onSimStopped(); } + + // If the simulation stops, the model will be reloaded when it is restarted. + dataDefinitionModel = NULL; + + break; + } + case SystemEventPause: + { + const bool paused = event->dwData ? true : false; + if (simulatorMsfs2024->m_simPaused != paused) + { + simulatorMsfs2024->m_simPaused = paused; + simulatorMsfs2024->emitSimulatorCombinedStatus(); + } + break; + } + default: break; + } + break; // SIMCONNECT_RECV_ID_EVENT + } + case SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE: + { + const SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *event = + static_cast(pData); + const DWORD objectId = event->dwData; + const SIMCONNECT_SIMOBJECT_TYPE objectType = event->eObjType; + if (objectType != SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT && objectType != SIMCONNECT_SIMOBJECT_TYPE_HELICOPTER) + { + break; // SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE + } + + // such an object is not necessarily one of ours + // for instance, I always see object "5" when I start the simulator + if (simulatorMsfs2024->getSimConnectObjects().isKnownSimObjectId(objectId)) + { + switch (event->uEventID) + { + case SystemEventObjectRemoved: simulatorMsfs2024->simulatorReportedObjectRemoved(objectId); break; + case SystemEventObjectAdded: + // added in SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID + // this event here is normally received before SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID + break; + default: break; + } + } + break; // SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE + } + case SIMCONNECT_RECV_ID_EVENT_FRAME: + { + const SIMCONNECT_RECV_EVENT_FRAME *event = static_cast(pData); + switch (event->uEventID) + { + case SystemEventFrame: + // doing interpolation + simulatorMsfs2024->onSimFrame(); + break; + default: break; + } + break; // SIMCONNECT_RECV_ID_EVENT_FRAME + } + case SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID: + { + const SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast(pData); + const DWORD requestId = event->dwRequestID; + const DWORD objectId = event->dwObjectID; + + const QString Test = CSimulatorMsfs2024::requestIdToString(requestId); + + simulatorMsfs2024->m_dispatchRequestIdLast = requestId; + + if (CSimulatorMsfs2024::isRequestForSimConnectObject(requestId)) + { + bool success = simulatorMsfs2024->setSimConnectObjectId(requestId, objectId); + if (!success) { break; } // not an request ID of ours + success = simulatorMsfs2024->simulatorReportedObjectAdded( + objectId); // adding failed (no IDs), trigger follow up actions + if (!success) + { + // getting here would mean object was removed in the meantime + // otherwise we will detect it in verification + const CSimConnectObject simObject = simulatorMsfs2024->getSimObjectForObjectId(objectId); + const CSimulatedAircraft remoteAircraft(simObject.getAircraft()); + const CStatusMessage msg = + CStatusMessage(simulatorMsfs2024).error(u"Cannot add object %1, cs: '%2' model: '%3'") + << objectId << remoteAircraft.getCallsignAsString() << remoteAircraft.getModelString(); + CLogMessage::preformatted(msg); + emit simulatorMsfs2024->physicallyAddingRemoteModelFailed(remoteAircraft, false, false, msg); + } + } + break; // SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID + } + case SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE: + { + const SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = + static_cast(pData); + const DWORD requestId = pObjData->dwRequestID; + + switch (pObjData->dwRequestID) + { + + case 0: + { + break; + } + case 1: + { + dataDefinitionModel = reinterpret_cast(&pObjData->dwData); + if (dataDefinitionModel->title != NULL && dataDefinitionModel->livery != NULL) + { + CAircraftModel model(dataDefinitionModel->title, dataDefinitionModel->livery, + CAircraftModel::TypeOwnSimulatorModel); + + simulatorMsfs2024->reverseLookupAndUpdateOwnAircraftModel(model.getMsfs2024Modelstring()); + } + break; + } + + default: printf("Unhandled SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE received: %d\n", requestId); break; + } + break; + + break; + } + case SIMCONNECT_RECV_ID_SIMOBJECT_DATA: + { + const SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = static_cast(pData); + const DWORD requestId = pObjData->dwRequestID; + simulatorMsfs2024->m_dispatchRequestIdLast = requestId; + + switch (requestId) + { + case CSimConnectDefinitions::RequestOwnAircraft: + { + static_assert(sizeof(DataDefinitionOwnAircraft) == 45 * sizeof(double), + "DataDefinitionOwnAircraft has an incorrect size."); + const DataDefinitionOwnAircraft *ownAircaft = + reinterpret_cast(&pObjData->dwData); + simulatorMsfs2024->updateOwnAircraftFromSimulator(*ownAircaft); + break; + } + case CSimConnectDefinitions::RequestMSFSTransponder: + { + const DataDefinitionMSFSTransponderMode *transponderMode = + reinterpret_cast(&pObjData->dwData); + simulatorMsfs2024->updateMSFSTransponderMode(*transponderMode); + break; + } + default: + { + const DWORD objectId = pObjData->dwObjectID; + if (CSimulatorMsfs2024::isRequestForSimObjAircraft(requestId)) + { + const CSimConnectObject simObject = simulatorMsfs2024->getSimObjectForObjectId(objectId); + if (!simObject.hasValidRequestAndObjectId()) { break; } + const CSimConnectDefinitions::SimObjectRequest subRequest = + CSimulatorMsfs2024::requestToSimObjectRequest(requestId); + + if (subRequest == CSimConnectDefinitions::SimObjectPositionData) + { + static_assert(sizeof(DataDefinitionPosData) == 5 * sizeof(double), + "DataDefinitionPosData has an incorrect size."); + const DataDefinitionPosData *remoteAircraftSimData = + reinterpret_cast(&pObjData->dwData); + // extra check, but ids should be the same + if (objectId == simObject.getObjectId()) + { + simulatorMsfs2024->triggerUpdateRemoteAircraftFromSimulator(simObject, + *remoteAircraftSimData); + } + } // position + else if (subRequest == CSimConnectDefinitions::SimObjectModel) + { + static_assert(sizeof(DataDefinitionRemoteAircraftModel) == sizeof(double) + 168 + 256, + "DataDefinitionRemoteAircraftModel has an incorrect size."); + const DataDefinitionRemoteAircraftModel *remoteAircraftModel = + reinterpret_cast(&pObjData->dwData); + // extra check, but ids should be the same + if (objectId == simObject.getObjectId()) + { + simulatorMsfs2024->triggerUpdateRemoteAircraftFromSimulator(simObject, + *remoteAircraftModel); + } + } // model + else if (subRequest == CSimConnectDefinitions::SimObjectLights) + { + static_assert(sizeof(DataDefinitionRemoteAircraftLights) == 8 * sizeof(double), + "DataDefinitionRemoteAircraftLights has an incorrect size."); + const DataDefinitionRemoteAircraftLights *remoteAircraftLights = + reinterpret_cast(&pObjData->dwData); + // extra check, but ids should be the same + if (objectId == simObject.getObjectId()) + { + const CCallsign callsign(simObject.getCallsign()); + const CAircraftLights lights(remoteAircraftLights->toLights()); // as in simulator + simulatorMsfs2024->setCurrentLights(callsign, lights); + if (simObject.getLightsAsSent().isNull()) + { + // allows to compare for toggle + simulatorMsfs2024->setLightsAsSent(callsign, lights); + } + } + break; + } // lights + else + { + if (CBuildConfig::isLocalDeveloperDebugBuild()) + { + CLogMessage(simulatorMsfs2024).error(u"Unknown subrequest (aircraft): '%1' %2") + << CSimConnectDefinitions::simObjectRequestToString(subRequest) + << simObject.toQString(); + } + } + } + else if (CSimulatorMsfs2024::isRequestForSimObjTerrainProbe(requestId)) + { + const CSimConnectObject probeObj = simulatorMsfs2024->getSimObjectForObjectId(objectId); + if (!probeObj.hasValidRequestAndObjectId()) { break; } + Q_ASSERT_X(probeObj.isTerrainProbe(), Q_FUNC_INFO, "No probe"); + const CSimConnectDefinitions::SimObjectRequest subRequest = + CSimulatorMsfs2024::requestToSimObjectRequest(requestId); + + if (subRequest == CSimConnectDefinitions::SimObjectPositionData) + { + static_assert(sizeof(DataDefinitionPosData) == 5 * sizeof(double), + "DataDefinitionRemoteAircraftSimData has an incorrect size."); + const DataDefinitionPosData *probeSimData = + reinterpret_cast(&pObjData->dwData); + // extra check, but ids should be the same + if (objectId == probeObj.getObjectId()) + { + const CCallsign cs = simulatorMsfs2024->m_pendingProbeRequests.value(requestId); + if (cs.isEmpty()) { break; } + simulatorMsfs2024->updateProbeFromSimulator(cs, *probeSimData); + } + } + else + { + if (CBuildConfig::isLocalDeveloperDebugBuild()) + { + CLogMessage(simulatorMsfs2024).error(u"Unknown subrequest (probe): '%1' %2") + << CSimConnectDefinitions::simObjectRequestToString(subRequest) << probeObj.toQString(); + } + } + } // probe + } + break; // default (SIMCONNECT_RECV_ID_SIMOBJECT_DATA) + } + break; // SIMCONNECT_RECV_ID_SIMOBJECT_DATA + } + case SIMCONNECT_RECV_ID_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST: // 38 + { + if (m_generic.getPropertyModelSet()) + { + SIMCONNECT_RECV_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST *msg = + (SIMCONNECT_RECV_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST *)pData; + switch (msg->dwRequestID) + { + // case CSimConnectDefinitions::REQUEST_ALL: + // case CSimConnectDefinitions::REQUEST_USER: + // case CSimConnectDefinitions::REQUEST_BOAT: + // case CSimConnectDefinitions::REQUEST_GROUND: + // case CSimConnectDefinitions::REQUEST_ANIMAL: + case CSimConnectDefinitions::REQUEST_AIRPLANE: + case CSimConnectDefinitions::REQUEST_HELICOPTER: + case CSimConnectDefinitions::REQUEST_HOT_AIR: simulatorMsfs2024->CacheSimObjectAndLiveries(msg); break; + } + } + + break; + } + case SIMCONNECT_RECV_ID_CLIENT_DATA: + { + if (!simulatorMsfs2024->m_useSbOffsets) { break; } + simulatorMsfs2024->m_sbDataReceived++; + const SIMCONNECT_RECV_CLIENT_DATA *clientData = static_cast(pData); + if (clientData->dwRequestID == CSimConnectDefinitions::RequestSbData) + { + //! \fixme FSUIPC vs SimConnect why is offset 19 ident 2/0? In FSUIPC it is 0/1, according to + //! documentation it is 0/1 but I receive 2/0 here. Whoever knows, add comment or fix if wrong + DataDefinitionClientAreaSb sbData; + std::memcpy(&sbData.data, &clientData->dwData, 128); + simulatorMsfs2024->updateOwnAircraftFromSimulator(sbData); + } + break; // SIMCONNECT_RECV_ID_CLIENT_DATA + } + case SIMCONNECT_RECV_ID_EVENT_FILENAME: + { + const SIMCONNECT_RECV_EVENT_FILENAME *event = static_cast(pData); + switch (event->uEventID) + { + case SystemEventFlightLoaded: break; + default: break; + } + break; // SIMCONNECT_RECV_ID_EVENT_FILENAME + } + default: simulatorMsfs2024->m_dispatchProcEmptyCount++; break; + } // main switch + + // performance stats + const qint64 procTimeEnd = QDateTime::currentMSecsSinceEpoch(); + simulatorMsfs2024->m_dispatchProcTimeMs = procTimeEnd - procTimeStart; + if (simulatorMsfs2024->m_dispatchProcTimeMs > simulatorMsfs2024->m_dispatchProcMaxTimeMs) + { + simulatorMsfs2024->m_dispatchProcMaxTimeMs = simulatorMsfs2024->m_dispatchProcTimeMs; + } + } // method +} // namespace swift::simplugin::msfs2024common diff --git a/src/swiftdata/CMakeLists.txt b/src/swiftdata/CMakeLists.txt index 1dc6536e9a..22ccfd48f0 100644 --- a/src/swiftdata/CMakeLists.txt +++ b/src/swiftdata/CMakeLists.txt @@ -7,6 +7,8 @@ add_executable(swiftdata WIN32 swiftdata.h swiftdata.ui swiftdatamenus.cpp + swiftdataapplication.cpp + swiftdataapplication.h ) if(WIN32) diff --git a/src/swiftdata/main.cpp b/src/swiftdata/main.cpp index e8d80900a3..2b01ba6e29 100644 --- a/src/swiftdata/main.cpp +++ b/src/swiftdata/main.cpp @@ -11,6 +11,7 @@ #include "misc/crashhandler.h" #include "misc/icons.h" #include "swiftdata.h" +#include "swiftdataapplication.h" using namespace swift::misc; using namespace swift::core; @@ -23,19 +24,25 @@ int main(int argc, char *argv[]) Q_UNUSED(qa) CCrashHandler::instance()->init(); - CGuiApplication a(CApplicationInfo::swiftMappingTool(), CApplicationInfo::MappingTool, CIcons::swiftDatabase48()); - if (!a.parseCommandLineArgsAndLoadSetup()) { return EXIT_FAILURE; } - a.splashScreen(CIcons::swiftDatabase256()); - a.initAndStartWebDataServices(swift::core::CWebReaderFlags::AllSwiftDbReaders, - CDatabaseReaderConfigList::forMappingTool()); - a.startCoreFacadeWithoutContexts(); - if (!a.start()) + + int r = 0; { - a.gracefulShutdown(); - return EXIT_FAILURE; + // CGuiApplication a(CApplicationInfo::swiftMappingTool(), CApplicationInfo::MappingTool, + // CIcons::swiftDatabase48()); + CSwiftDataApplication a; // application with contexts + if (!a.parseCommandLineArgsAndLoadSetup()) { return EXIT_FAILURE; } + a.splashScreen(CIcons::swiftDatabase256()); + a.initAndStartWebDataServices(swift::core::CWebReaderFlags::AllSwiftDbReaders, + CDatabaseReaderConfigList::forMappingTool()); + a.startCoreFacadeWithoutContexts(); + if (!a.start()) + { + a.gracefulShutdown(); + return EXIT_FAILURE; + } + CSwiftData w; + w.show(); + int r = a.exec(); } - CSwiftData w; - w.show(); - int r = a.exec(); return r; } diff --git a/src/swiftdata/swiftdata.h b/src/swiftdata/swiftdata.h index 4989e913dd..602e1a7791 100644 --- a/src/swiftdata/swiftdata.h +++ b/src/swiftdata/swiftdata.h @@ -25,7 +25,8 @@ namespace Ui namespace swift::core { class CWebDataServices; -} + // class CPluginManagerSimulator; +} // namespace swift::core namespace swift::gui::components { class CAutoPublishDialog; diff --git a/src/swiftdata/swiftdataapplication.cpp b/src/swiftdata/swiftdataapplication.cpp new file mode 100644 index 0000000000..46d52bf9e6 --- /dev/null +++ b/src/swiftdata/swiftdataapplication.cpp @@ -0,0 +1,106 @@ +// SPDX-FileCopyrightText: Copyright (C) 2016 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +#include "swiftdataapplication.h" + +#include + +#include "core/application.h" +#include "core/corefacadeconfig.h" +#include "core/coremodeenums.h" +#include "misc/dbusserver.h" +#include "misc/icons.h" + +using namespace swift::misc; +using namespace swift::core; + +CSwiftDataApplication::CSwiftDataApplication() + : CGuiApplication(CApplicationInfo::swiftMappingTool(), CApplicationInfo::MappingTool, CIcons::swiftDatabase48()) +{ + // this->addParserOption(m_cmdFacadeMode); + // this->addDBusAddressOption(); + // this->addNetworkOptions(); + // this->addAudioOptions(); +} + +// TODO TZ remove commented code after testing +CStatusMessageList CSwiftDataApplication::startHookIn() +{ + Q_ASSERT_X(m_parsed, Q_FUNC_INFO, "Not yet parsed cmd line arguments"); + + QString dBusAddress(this->getCmdDBusAddressValue()); + const QString coreModeStr = + this->isParserOptionSet(m_cmdFacadeMode) ? this->getParserValue(m_cmdFacadeMode) : QString(); + CoreModes::CoreMode coreMode = CoreModes::stringToCoreMode(coreModeStr); + + //// Valid combination? + // if (!coreModeStr.isEmpty()) + //{ + // if (coreMode == CoreModes::Standalone && !dBusAddress.isEmpty()) + // { + // const CStatusMessage m = + // CStatusMessage(this, CLogCategories::validation()).error(u"Inconsistent pair DBus: '%1' and core: + // '%2'") + // << dBusAddress << coreModeStr; + // return CStatusMessageList(m); + // } + // } + + //// Implicit configuration + CStatusMessageList msgs; + // if (!dBusAddress.isEmpty() && coreModeStr.isEmpty()) + //{ + // coreMode = CoreModes::Distributed; // default + // const CStatusMessage m = + // CStatusMessage(this, CLogCategories::validation()).info(u"No DBus address, setting core mode: '%1'") + // << CoreModes::coreModeToString(coreMode); + // msgs.push_back(m); + // } + // else if (dBusAddress.isEmpty() && coreMode == CoreModes::Distributed) + //{ + // dBusAddress = CDBusServer::sessionBusAddress(); // a possible default + // const CStatusMessage m = + // CStatusMessage(this, CLogCategories::validation()).info(u"Setting DBus address to '%1'") << dBusAddress; + // msgs.push_back(m); + // } + + CCoreFacadeConfig runtimeConfig = coreModeToCoreFacadeConfig(coreMode, dBusAddress); + const CStatusMessageList contextMsgs = this->initContextsAndStartCoreFacade(runtimeConfig); + // const CStatusMessageList contextMsgs = { CStatusMessage(this, CLogCategories::validation()).info(u"TEST") }; + msgs.push_back(contextMsgs); + return contextMsgs; +} + +bool CSwiftDataApplication::parsingHookIn() +{ + // Parse core relevant arguments + const QString dBusAddress(this->getCmdDBusAddressValue()); + // if (!dBusAddress.isEmpty()) + //{ + // // check if reachable + // if (!CDBusServer::isDBusAvailable(dBusAddress)) + // { + // this->cmdLineErrorMessage("DBus error", "DBus server at '" + dBusAddress + "' can not be reached"); + // return false; + // } + // } + return CGuiApplication::parsingHookIn(); +} + +CSwiftDataApplication *CSwiftDataApplication::instance() +{ + return qobject_cast(CApplication::instance()); +} + +CCoreFacadeConfig CSwiftDataApplication::coreModeToCoreFacadeConfig(CoreModes::CoreMode coreMode, + const QString &dBusAddress) +{ + switch (coreMode) + { + case CoreModes::Distributed: return CCoreFacadeConfig(CCoreFacadeConfig::Remote, dBusAddress); + case CoreModes::Standalone: return CCoreFacadeConfig(CCoreFacadeConfig::Local, dBusAddress); break; + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Not handled core mode"); + return CCoreFacadeConfig(CCoreFacadeConfig::NotUsed, dBusAddress); + } +} diff --git a/src/swiftdata/swiftdataapplication.h b/src/swiftdata/swiftdataapplication.h new file mode 100644 index 0000000000..50c5168629 --- /dev/null +++ b/src/swiftdata/swiftdataapplication.h @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: Copyright (C) 2016 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +//! \file + +#ifndef SWIFTDATAAPPLICATION_H +#define SWIFTDATAAPPLICATION_H + +#include +#include +#include +#include + +#include "core/coremodeenums.h" +#include "gui/guiapplication.h" + +/*! + * Specialized GUI application for swift pilot client. + * Handles parsing of some specialized CMD line argumenets and startup of core + */ +class CSwiftDataApplication : public swift::gui::CGuiApplication +{ + Q_OBJECT + +public: + //! Constructor + CSwiftDataApplication(); + + //! Single instance + CSwiftDataApplication *instance(); + +protected: + //! Parsing of special CMD args + virtual bool parsingHookIn() override; + + //! Start facade by cmd arguments + virtual swift::misc::CStatusMessageList startHookIn() override; + +private: + static swift::core::CCoreFacadeConfig coreModeToCoreFacadeConfig(swift::core::CoreModes::CoreMode, + const QString &dBusAddress); + + QCommandLineOption m_cmdFacadeMode { { "c", "core" }, + QCoreApplication::translate("main", "Core mode: (d)istributed, (s)tandalone."), + "coremode" }; //!< Facade startup mode +}; + +#endif // SWIFTDATAAPPLICATION_H From 6700f66e1cde551ad251ed98ba4d1ccc258a8e46 Mon Sep 17 00:00:00 2001 From: tzobler Date: Wed, 5 Nov 2025 12:04:36 +0100 Subject: [PATCH 2/8] fix: Annotations from GitHub build resolved --- src/misc/simulation/settings/simulatorsettings.cpp | 1 - .../simulator/msfs2024/simconnectsymbolsmsfs2024.cpp | 4 ++-- src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp | 6 ++---- .../simulator/msfs2024/simulatormsfs2024simconnectproc.cpp | 2 -- src/swiftdata/main.cpp | 2 +- src/swiftdata/swiftdataapplication.cpp | 2 +- 6 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/misc/simulation/settings/simulatorsettings.cpp b/src/misc/simulation/settings/simulatorsettings.cpp index cc5581676e..64599a592e 100644 --- a/src/misc/simulation/settings/simulatorsettings.cpp +++ b/src/misc/simulation/settings/simulatorsettings.cpp @@ -707,7 +707,6 @@ namespace swift::misc::simulation::settings // msfs2024 uses no model directories but uses the field "packages directory" for filtering modelstrings // Asterix stands for everything == no filtering static const QString msfs2024 = "*"; - if (msfs2024.isEmpty()) { return e; } static const QStringList md { msfs2024 }; return md; } diff --git a/src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.cpp b/src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.cpp index 0396cebdb8..68aaadfe0a 100644 --- a/src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.cpp +++ b/src/plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.cpp @@ -120,7 +120,7 @@ using PfnSimConnect_AICreateSimulatedObject_EX1 = HRESULT(__stdcall *)(HANDLE, c //! The SimConnect Symbols //! \private -struct SimConnectSymbols +struct SimConnectSymbolsMsfs2024 { PfnSimConnect_Open SimConnect_Open = nullptr; PfnSimConnect_Close SimConnect_Close = nullptr; @@ -169,7 +169,7 @@ struct SimConnectSymbols #endif }; -static SimConnectSymbols gSymbols; +static SimConnectSymbolsMsfs2024 gSymbols; template bool resolveSimConnectSymbol(QLibrary &library, FuncPtr &funcPtr, const char *funcName) diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp index 33bcd7895f..14d25369f4 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp @@ -513,17 +513,15 @@ namespace swift::simplugin::msfs2024common bool incremnental = true; bool sortByDistributor = true; bool consolidateWithDb = false; - bool ShowAllInstalledModells = true; + bool ShowAllInstalledModells = true; // msfs20424 always show all installed models if (gui_application) { givenDistributorsOnly = m_generic.getPropertyDistributorFiltered(); dbDataOnly = m_generic.getPropertyWithDbEntry(); - dbIcaoOnly = false; incremnental = false; - sortByDistributor = true; consolidateWithDb = true; - ShowAllInstalledModells = true; // msfs20424 always show all installed models + ShowAllInstalledModells = true; } // CDistributorList distributorList; diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp index 4517b2d031..9d6158cb2d 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp @@ -221,8 +221,6 @@ namespace swift::simplugin::msfs2024common const DWORD requestId = event->dwRequestID; const DWORD objectId = event->dwObjectID; - const QString Test = CSimulatorMsfs2024::requestIdToString(requestId); - simulatorMsfs2024->m_dispatchRequestIdLast = requestId; if (CSimulatorMsfs2024::isRequestForSimConnectObject(requestId)) diff --git a/src/swiftdata/main.cpp b/src/swiftdata/main.cpp index 2b01ba6e29..b0ea5384af 100644 --- a/src/swiftdata/main.cpp +++ b/src/swiftdata/main.cpp @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) } CSwiftData w; w.show(); - int r = a.exec(); + r = a.exec(); } return r; } diff --git a/src/swiftdata/swiftdataapplication.cpp b/src/swiftdata/swiftdataapplication.cpp index 46d52bf9e6..699f12ff14 100644 --- a/src/swiftdata/swiftdataapplication.cpp +++ b/src/swiftdata/swiftdataapplication.cpp @@ -74,7 +74,7 @@ CStatusMessageList CSwiftDataApplication::startHookIn() bool CSwiftDataApplication::parsingHookIn() { // Parse core relevant arguments - const QString dBusAddress(this->getCmdDBusAddressValue()); + // const QString dBusAddress(this->getCmdDBusAddressValue()); // if (!dBusAddress.isEmpty()) //{ // // check if reachable From f034d316941a177ce0395fca02553a657f07985e Mon Sep 17 00:00:00 2001 From: tzobler Date: Fri, 7 Nov 2025 22:09:24 +0100 Subject: [PATCH 3/8] feat: Implementation of the msfs2024 model mapping is ready for testing --- src/core/aircraftmatcher.cpp | 8 +++ src/core/airspacemonitor.cpp | 56 +++++++++++++++---- src/core/context/contextnetworkimpl.cpp | 5 ++ src/core/simulator.cpp | 9 +++ src/gui/components/logincomponent.cpp | 13 ++++- src/gui/components/mappingcomponent.cpp | 22 +++++++- src/gui/components/mappingcomponent.h | 3 + src/misc/simulation/simulatedaircraft.h | 5 +- .../simconnectdatadefinitionmsfs2024.h | 3 +- .../msfs2024/simulatormsfs2024common.cpp | 43 +++++++------- .../msfs2024/simulatormsfs2024common.h | 2 +- .../simulatormsfs2024simconnectproc.cpp | 4 +- 12 files changed, 136 insertions(+), 37 deletions(-) diff --git a/src/core/aircraftmatcher.cpp b/src/core/aircraftmatcher.cpp index 1fb68626cb..4fcee6fe89 100644 --- a/src/core/aircraftmatcher.cpp +++ b/src/core/aircraftmatcher.cpp @@ -1710,6 +1710,14 @@ namespace swift::core const QString &livery) { Q_UNUSED(livery) + // TODO TZ remove after testing + CLogMessage(this).info(u"CAircraftMatcher::onIcaoCodesReceived CHECK:" + u"callsign %1 " + u"aircraftIcao %2 " + u"airlineIcao %3 " + u"livery %4 ") + << callsign << aircraftIcao << airlineIcao << livery; + Q_ASSERT_X(sApp && sApp->hasWebDataServices(), Q_FUNC_INFO, "Missing web data services"); if (m_modelSet.isEmpty()) { return; } // ignore empty sets to not create silly stats if (sessionId.isEmpty()) { return; } diff --git a/src/core/airspacemonitor.cpp b/src/core/airspacemonitor.cpp index b4bdc515d3..da443ffcf2 100644 --- a/src/core/airspacemonitor.cpp +++ b/src/core/airspacemonitor.cpp @@ -773,6 +773,14 @@ namespace swift::core const QString &aircraftIcaoDesignator, const QString &combinedAircraftType, const QString &modelString) { + // TODO TZ remove when testing is done + CLogMessage(this).info(u"CAirspaceMonitor::onCustomFSInnPacketReceived CHECK:" + u"callsign %1 " + u"airlineIcaoDesignator %2 " + u"aircraftIcaoDesignator %3 " + u"modelString %4 ") + << callsign << airlineIcaoDesignator << aircraftIcaoDesignator << modelString; + // it can happen this is called before any queries // ES sends FsInn packets for callsigns such as ACCGER1, which are hard to distinguish // 1) checking if they are already in the list checks again ATC position which is safe @@ -834,9 +842,9 @@ namespace swift::core // in order not to override swift livery string data, we ignore those if (!usedModelString.isEmpty()) { - this->addOrUpdateAircraftInRange(callsign, aircraftIcaoDesignator, airlineIcaoDesignator, QString(), - usedModelString, CAircraftModel::TypeFSInnData, - pReverseLookupMessages); + const CSimulatedAircraft aircraft = this->addOrUpdateAircraftInRange( + callsign, aircraftIcaoDesignator, airlineIcaoDesignator, QString(), usedModelString, + CAircraftModel::TypeFSInnData, pReverseLookupMessages); this->addReverseLookupMessages(callsign, reverseLookupMessages); } this->sendReadyForModelMatching(callsign, ReceivedFsInnPacket); // from FSInn @@ -846,6 +854,14 @@ namespace swift::core void CAirspaceMonitor::onIcaoCodesReceived(const CCallsign &callsign, const QString &aircraftIcaoDesignator, const QString &airlineIcaoDesignator, const QString &livery) { + // TODO TZ remove when testing is done + CLogMessage(this).info(u"CAirspaceMonitor::onIcaoCodesReceived CHECK:" + u"callsign %1 " + u"aircraftIcaoDesignator %2 " + u"airlineIcaoDesignator %3 " + u"livery %4 ") + << callsign << aircraftIcaoDesignator << airlineIcaoDesignator << livery; + Q_ASSERT_X(CThreadUtils::isInThisThread(this), Q_FUNC_INFO, "not in main thread"); if (!this->isConnectedAndNotShuttingDown()) { return; } if (CBuildConfig::isLocalDeveloperDebugBuild()) @@ -865,13 +881,16 @@ namespace swift::core CAirspaceMonitor::getLogCategories()); const CClient client = this->getClientOrDefaultForCallsign(callsign); - this->addOrUpdateAircraftInRange(callsign, aircraftIcaoDesignator, airlineIcaoDesignator, livery, - client.getQueriedModelString(), CAircraftModel::TypeQueriedFromNetwork, - pReverseLookupMessages); - this->addReverseLookupMessages(callsign, reverseLookupMessages); - this->sendReadyForModelMatching(callsign, ReceivedIcaoCodes); // ICAO codes received + const CSimulatedAircraft aircraft = this->addOrUpdateAircraftInRange( + callsign, aircraftIcaoDesignator, airlineIcaoDesignator, livery, client.getQueriedModelString(), + CAircraftModel::TypeQueriedFromNetwork, pReverseLookupMessages); + if (aircraft.getModel().getModelType() != CAircraftModel::TypeManuallySet) + { + this->addReverseLookupMessages(callsign, reverseLookupMessages); + this->sendReadyForModelMatching(callsign, ReceivedIcaoCodes); // ICAO codes received - emit this->requestedNewAircraft(callsign, aircraftIcaoDesignator, airlineIcaoDesignator, livery); + emit this->requestedNewAircraft(callsign, aircraftIcaoDesignator, airlineIcaoDesignator, livery); + } } CAircraftModel CAirspaceMonitor::reverseLookupModelWithFlightplanData( @@ -1178,9 +1197,26 @@ namespace swift::core const CSimulatedAircraft aircraft = this->getAircraftInRangeForCallsign(callsign); if (aircraft.hasValidCallsign()) { + // TODO TZ at this point we have a poblem if the model has no DB key yet (msfs2024 liveries) // only if we do not have a DB model yet - if (!aircraft.getModel().hasValidDbKey()) + // int testType = aircraft.getModelType();1 + CLogMessage(this).info(u"CAirspaceMonitor::addOrUpdateAircraftInRange CHECK:" + u"aircraft.getModelType %1 " + u"callsign %2 " + u"aircraftIcao %3 " + u"incomming modelType %4 ") + << aircraft.getModelType() << callsign.toQString() << aircraftIcao << modelType; + + if (!aircraft.getModel().hasValidDbKey() && aircraft.getModelType() != CAircraftModel::TypeManuallySet) { + + CLogMessage(this).warning(u"CAirspaceMonitor::reverseLookupModelWithFlightplanData " + u"aircraft.getModelType %1 " + u"callsign %2 " + u"aircraftIcao %3 " + u"incomming modelType %4 ") + << aircraft.getModelType() << callsign.toQString() << aircraftIcao << modelType; + CAircraftModel model = this->reverseLookupModelWithFlightplanData(callsign, aircraftIcao, airlineIcao, livery, modelString, modelType, log); model.updateMissingParts(aircraft.getModel()); diff --git a/src/core/context/contextnetworkimpl.cpp b/src/core/context/contextnetworkimpl.cpp index f8c0e237ab..63ac22a408 100644 --- a/src/core/context/contextnetworkimpl.cpp +++ b/src/core/context/contextnetworkimpl.cpp @@ -1142,6 +1142,11 @@ namespace swift::core::context if (c) { const CSimulatedAircraft aircraft(this->getAircraftInRangeForCallsign(callsign)); + // TODO TZ + CLogMessage(this).info(u"CContextNetwork::updateAircraftModel model.getModelString %1 model.getModelLivery " + u"%2 model.getModelType %3 aircraft.getModelType '%4'") + << model.getModelString() << model.getModelLivery() << model.getModelType() << aircraft.getModelType(); + Q_ASSERT_X(!aircraft.getCallsign().isEmpty(), Q_FUNC_INFO, "missing callsign"); emit this->changedRemoteAircraftModel(aircraft, originator); // update aircraft model } diff --git a/src/core/simulator.cpp b/src/core/simulator.cpp index 69bef852f4..7af290c344 100644 --- a/src/core/simulator.cpp +++ b/src/core/simulator.cpp @@ -981,6 +981,15 @@ namespace swift::core bool ISimulator::changeRemoteAircraftEnabled(const CSimulatedAircraft &aircraft) { if (this->isShuttingDown()) { return false; } + + // TODO TZ remove after testing + CLogMessage(this).info(u"ISimulator::changeRemoteAircraftEnabled CHECK:" + u"aircraft.getModelType %1 " + u"aircraft.getModelString %2 " + u"aircraft.getLiveryString %3 ") + << aircraft.getModelType() << aircraft.getModelString() << aircraft.getLiveryString(); + ; + return aircraft.isEnabled() ? this->physicallyAddRemoteAircraft(aircraft) : this->physicallyRemoveRemoteAircraft(aircraft.getCallsign()); } diff --git a/src/gui/components/logincomponent.cpp b/src/gui/components/logincomponent.cpp index b306b7182b..507c3c10a0 100644 --- a/src/gui/components/logincomponent.cpp +++ b/src/gui/components/logincomponent.cpp @@ -41,6 +41,9 @@ #include "misc/logmessage.h" #include "misc/network/connectionstatus.h" #include "misc/network/entityflags.h" +// TODO TZ remove afte testing +#include "misc/network/server.h" +// TODO TZ end remove afte testing #include "misc/network/serverlist.h" #include "misc/simulation/aircraftmodel.h" #include "misc/simulation/simulatedaircraft.h" @@ -298,8 +301,14 @@ namespace swift::gui::components { if (!m_updatePilotOnServerChanges) { return; } const bool vatsim = this->isVatsimNetworkTabSelected(); - const CUser user = vatsim ? this->getCurrentVatsimServer().getUser() : server.getUser(); - ui->form_Pilot->setUser(user); + // TODO TZ remove after testing + // const CUser user = vatsim ? this->getCurrentVatsimServer().getUser() : server.getUser(); + const CUser user = + server.getServerType() != CServer::FSDServer ? this->getCurrentVatsimServer().getUser() : server.getUser(); + if ((vatsim && server.getServerType() != CServer::FSDServer) || + (!vatsim && server.getServerType() == CServer::FSDServer)) + // End remove after testing + ui->form_Pilot->setUser(user); } void CLoginComponent::onSimulatorStatusChanged(int status) diff --git a/src/gui/components/mappingcomponent.cpp b/src/gui/components/mappingcomponent.cpp index f10c295910..6ee3695e47 100644 --- a/src/gui/components/mappingcomponent.cpp +++ b/src/gui/components/mappingcomponent.cpp @@ -84,6 +84,7 @@ namespace swift::gui::components &CMappingComponent::onModelsUpdateRequested); connect(ui->tvp_AircraftModels, &CAircraftModelView::modelDataChanged, this, &CMappingComponent::onRowCountChanged); + connect(ui->tvp_AircraftModels, &CAircraftModelView::clicked, this, &CMappingComponent::onModelSelectedInView); connect(ui->tvp_AircraftModels, &CAircraftModelView::requestTempDisableModelsForMatching, this, &CMappingComponent::onTempDisableModelsForMatchingRequested); @@ -258,6 +259,12 @@ namespace swift::gui::components ui->completer_ModelStrings->setModel(simAircraft.getModel()); } + void CMappingComponent::onModelSelectedInView(const QModelIndex &index) + { + const CAircraftModel model = ui->tvp_AircraftModels->at(index); + ui->completer_ModelStrings->setModel(model); + } + CCallsign CMappingComponent::validateRenderedCallsign() { const QString cs = ui->le_Callsign->text().trimmed(); @@ -326,7 +333,10 @@ namespace swift::gui::components } const CCallsign callsign(this->validateRenderedCallsign()); if (callsign.isEmpty()) { return; } + + // Because of msfs2024, the model string contains the combination of title and livery. const QString modelString = ui->completer_ModelStrings->getModelString(); + if (modelString.isEmpty()) { this->showOverlayHTMLMessage(CStatusMessage(this).validationError(u"Missing model for mapping"), @@ -359,6 +369,13 @@ namespace swift::gui::components if (aircraftFromBackend.getModelString() != modelString) { const CAircraftModelList models = sGui->getIContextSimulator()->getModelSetModelsStartingWith(modelString); + + // TODO TZ DEBUG only for testing + const CStatusMessage msg = CStatusMessage(this).validationInfo(u"Found: %1 models for %2") + << models.size() << modelString; + this->showOverlayMessage(msg, OverlayMessageMs); + // END testing + if (models.isEmpty()) { const CStatusMessage msg = CStatusMessage(this).validationError(u"No model for title: '%1'") @@ -368,6 +385,7 @@ namespace swift::gui::components } CAircraftModel model(models.front()); + // found more than one model? if (models.size() > 1) { if (models.containsModelString(modelString)) @@ -384,8 +402,10 @@ namespace swift::gui::components model.setModelType(CAircraftModel::TypeManuallySet); CLogMessage(this).info(u"Requesting changes for '%1'") << callsign.asString(); - // enable in any case + // rendering-flag enable in any case sGui->getIContextNetwork()->updateAircraftEnabled(aircraftFromBackend.getCallsign(), true); + + // trigger model change changed = sGui->getIContextNetwork()->updateAircraftModel(aircraftFromBackend.getCallsign(), model, identifier()); } diff --git a/src/gui/components/mappingcomponent.h b/src/gui/components/mappingcomponent.h index 8e6a901bec..6812c4a689 100644 --- a/src/gui/components/mappingcomponent.h +++ b/src/gui/components/mappingcomponent.h @@ -113,6 +113,9 @@ namespace swift::gui //! Aircraft selected (in view) void onAircraftSelectedInView(const QModelIndex &index); + //! Model selected (in view) + void onModelSelectedInView(const QModelIndex &index); + //! Save changed aircraft void onSaveAircraft(); diff --git a/src/misc/simulation/simulatedaircraft.h b/src/misc/simulation/simulatedaircraft.h index 5dc31f20c5..87784dfac3 100644 --- a/src/misc/simulation/simulatedaircraft.h +++ b/src/misc/simulation/simulatedaircraft.h @@ -412,7 +412,7 @@ namespace swift::misc //! Get model Livery MSFS2024 const QString &getLiveryString() const { return m_models[CurrentModel].getModelLivery(); } - //! Get short model string (without livery) + //! Get short model string (without livery msfs2024) const QString getShortModelString() const { return m_models[CurrentModel].getShortModelString(); } //! Set model string @@ -492,6 +492,9 @@ namespace swift::misc //! \copydoc swift::misc::mixin::Icon::toIcon() CIcons::IconIndex toIcon() const { return m_callsign.toIcon(); } + //! Get model type + int getModelType() const { return m_models[CurrentModel].getModelType(); } + private: static constexpr int CurrentModel = 0; //!< m_models static constexpr int NetworkModel = 1; //!< m_models diff --git a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h index 1c2bd4571d..2503ea69a1 100644 --- a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h +++ b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h @@ -86,7 +86,7 @@ namespace swift::simplugin::msfs2024common struct DataDefinitionOwnAircraftModel { char title[256]; //!< Aircraft model string - char livery[256]; //!< Aircraft model string + char livery[256]; //!< Aircraft livery string msfs2024 }; //! Data struct of aircraft model data @@ -107,6 +107,7 @@ namespace swift::simplugin::msfs2024common char atcAirlineNumber[64]; //!< airline number char atcFlightNumber[8]; //!< flight number (168) char title[256]; //!< Aircraft model string + char livery[256]; //!< Aircraft livery string msfs2024 }; //! Data struct of aircraft data (setable) diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp index 14d25369f4..52e2f4be51 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp @@ -430,20 +430,16 @@ namespace swift::simplugin::msfs2024common // TODO TZ a message should be displayed here because the gui freezes during loading // better: move to the background (e.g., use CWorker::fromTask(...)), avoid GUI freeze. - this->createNewModelList(); - CLogMessage(this).info(u"%1 SimObjects and Liveries in vSimObjectsAndLiveries") << vSimObjectsAndLiveries.size(); - // Cannot create children for a parent that is in a different thread. - // owner = this (QObject in main thread) - // auto *worker = CWorker::fromTask(this, "createNewModelList", [=]() { - // this->createNewModelList(); - // return QVariant(); // void-Result - //}); - // TODO TZ where to place this message? - // worker->then(this, [=] { CLogMessage(this).info(u"SimObjects and Liveries in vSimObjectsAndLiveries ready"); - // }); + auto *worker = CWorker::fromTask(this, "createNewModelList", [=]() { + this->createNewModelList(); + return QVariant(); // void-Result + }); + + // TODO TZ where to place this message better? + worker->then(this, [=] { CLogMessage(this).info(u"SimObjects and Liveries in vSimObjectsAndLiveries ready"); }); } void CSimulatorMsfs2024::createNewModelList() @@ -475,6 +471,7 @@ namespace swift::simplugin::msfs2024common model.setModelString(modelLivery.szSimObjectCombinedTitle); model.setModelLivery(modelLivery.szLiveryName); model.setModelType(CAircraftModel::TypeOwnSimulatorModel); + if (!modelkey) model.setModelType(CAircraftModel::TypeManuallySet); model.setSimulator(this->getSimulatorInfo()); bool excluded = false; @@ -528,7 +525,7 @@ namespace swift::simplugin::msfs2024common // for (const QString &name : distributorNames) { distributorList.push_back(CDistributor(name)); } CDistributorList distributorList = sGui->getWebDataServices()->getDistributors(); - const CModelSetBuilder builder(this); + CModelSetBuilder builder(nullptr); CModelSetBuilder::Builder options = givenDistributorsOnly ? CModelSetBuilder::GivenDistributorsOnly : CModelSetBuilder::NoOptions; if (dbDataOnly) { options |= CModelSetBuilder::OnlyDbData; } @@ -1118,6 +1115,7 @@ namespace swift::simplugin::msfs2024common }); } + // called decoupled from simconnect event queue very fast void CSimulatorMsfs2024::updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionPosData &remoteAircraftData) { @@ -1170,6 +1168,7 @@ namespace swift::simplugin::msfs2024common } } + // called decoupled from simconnect event queue void CSimulatorMsfs2024::updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionRemoteAircraftModel &remoteAircraftModel) @@ -1179,7 +1178,11 @@ namespace swift::simplugin::msfs2024common CSimConnectObject &so = m_simConnectObjects[cs]; if (so.isPendingRemoved()) { return; } - const QString modelString(remoteAircraftModel.title); + // TODO TZ verify model and livery + QString combinedModelstring = + QString::fromUtf8(remoteAircraftModel.title) + " " + QString::fromUtf8(remoteAircraftModel.livery); + const QString modelString(combinedModelstring.trimmed()); + const CLength cg(remoteAircraftModel.cgToGroundFt, CLengthUnit::ft()); so.setAircraftCG(cg); so.setAircraftModelString(modelString); @@ -1230,7 +1233,7 @@ namespace swift::simplugin::msfs2024common this->updateCockpit(myAircraft.getCom1System(), myAircraft.getCom2System(), myXpdr, this->identifier()); } - void CSimulatorMsfs2024::updateMSFSTransponderMode(const DataDefinitionMSFSTransponderMode transponderMode) + void CSimulatorMsfs2024::updateMSFS2024TransponderMode(const DataDefinitionMSFSTransponderMode transponderMode) { auto mode = CTransponder::StateIdent; if (!transponderMode.ident) @@ -1390,9 +1393,10 @@ namespace swift::simplugin::msfs2024common CLogMessage(this).warning(u"Model failed to be added: '%1' details: %2") << simObject.getAircraftModelString() << simObject.getAircraft().toQString(true); - CStatusMessage verifyMsg; - const bool verifiedAircraft = this->verifyFailedAircraftInfo(simObject, verifyMsg); // aircraft.cfg existing? - if (!verifyMsg.isEmpty()) { CLogMessage::preformatted(verifyMsg); } + // CStatusMessage verifyMsg; + // const bool verifiedAircraft = this->verifyFailedAircraftInfo(simObject, verifyMsg); // aircraft.cfg existing? + const bool verifiedAircraft = true; + // if (!verifyMsg.isEmpty()) { CLogMessage::preformatted(verifyMsg); } CSimConnectObject simObjAddAgain(simObject); simObjAddAgain.increaseAddingExceptions(); @@ -1411,6 +1415,7 @@ namespace swift::simplugin::msfs2024common << simObjAddAgain.getAddingExceptions() : CLogMessage(this).warning(u"Model '%1' %2 failed verification and will be disabled") << simObjAddAgain.getAircraftModelString() << simObjAddAgain.toQString(); + this->updateAircraftEnabled(simObjAddAgain.getCallsign(), false); // disable emit this->physicallyAddingRemoteModelFailed(simObjAddAgain.getAircraft(), true, true, msg); // verify failed @@ -2007,8 +2012,8 @@ namespace swift::simplugin::msfs2024common .arg(fsxPositionToString(initialPosition))); } - const QByteArray modelStringBa = toFsxChar(modelString); - const QByteArray modelLiveryBa = toFsxChar(modelLiveryString); + const QByteArray modelStringBa = toFsxChar(modelString).trimmed(); + const QByteArray modelLiveryBa = toFsxChar(modelLiveryString).trimmed(); const QByteArray csBa = toFsxChar(callsign.toQString().left(12)); CSimConnectObject::SimObjectType type = CSimConnectObject::AircraftNonAtc; diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.h b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h index 464d2485ac..8bc491bce4 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024common.h +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h @@ -553,7 +553,7 @@ namespace swift::simplugin::msfs2024common void updateTransponderMode(const misc::aviation::CTransponder::TransponderMode xpdrMode); //! Update transponder mode from MSFS - void updateMSFSTransponderMode(const DataDefinitionMSFSTransponderMode transponderMode); + void updateMSFS2024TransponderMode(const DataDefinitionMSFSTransponderMode transponderMode); //! An AI aircraft was added in the simulator bool simulatorReportedObjectAdded(DWORD objectId); diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp index 9d6158cb2d..39cd5e391d 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp @@ -297,7 +297,7 @@ namespace swift::simplugin::msfs2024common { const DataDefinitionMSFSTransponderMode *transponderMode = reinterpret_cast(&pObjData->dwData); - simulatorMsfs2024->updateMSFSTransponderMode(*transponderMode); + simulatorMsfs2024->updateMSFS2024TransponderMode(*transponderMode); break; } default: @@ -325,7 +325,7 @@ namespace swift::simplugin::msfs2024common } // position else if (subRequest == CSimConnectDefinitions::SimObjectModel) { - static_assert(sizeof(DataDefinitionRemoteAircraftModel) == sizeof(double) + 168 + 256, + static_assert(sizeof(DataDefinitionRemoteAircraftModel) == sizeof(double) + 168 + 256 + 256, "DataDefinitionRemoteAircraftModel has an incorrect size."); const DataDefinitionRemoteAircraftModel *remoteAircraftModel = reinterpret_cast(&pObjData->dwData); From 0110146a74f19a03113b75fb6007627af8db4451 Mon Sep 17 00:00:00 2001 From: tzobler Date: Mon, 10 Nov 2025 13:50:25 +0100 Subject: [PATCH 4/8] fix: sortorder modelset --- src/core/airspacemonitor.cpp | 10 ++++-- src/gui/components/dbownmodelscomponent.cpp | 12 +++---- src/gui/models/aircraftmodellistmodel.cpp | 9 ++--- src/misc/simulation/aircraftmodel.cpp | 2 -- src/misc/simulation/aircraftmodel.h | 2 -- src/misc/simulation/aircraftmodelloader.cpp | 34 +++++++++---------- .../simconnectdatadefinitionmsfs2024.cpp | 4 +-- .../msfs2024/simulatormsfs2024common.cpp | 33 +++++++++++++++++- .../msfs2024/simulatormsfs2024common.h | 5 +++ 9 files changed, 71 insertions(+), 40 deletions(-) diff --git a/src/core/airspacemonitor.cpp b/src/core/airspacemonitor.cpp index da443ffcf2..2251acecdd 100644 --- a/src/core/airspacemonitor.cpp +++ b/src/core/airspacemonitor.cpp @@ -774,12 +774,14 @@ namespace swift::core const QString &combinedAircraftType, const QString &modelString) { // TODO TZ remove when testing is done + // #SBBER750:DAL483:FSIPIR:0:BER:A320:::::L2J:PMDG 737-800 AIRBERLIN (D-ABKM) CLogMessage(this).info(u"CAirspaceMonitor::onCustomFSInnPacketReceived CHECK:" u"callsign %1 " u"airlineIcaoDesignator %2 " u"aircraftIcaoDesignator %3 " - u"modelString %4 ") - << callsign << airlineIcaoDesignator << aircraftIcaoDesignator << modelString; + u"combinedAircraftType %4 " + u"modelString %5 ") + << callsign << airlineIcaoDesignator << aircraftIcaoDesignator << combinedAircraftType << modelString; // it can happen this is called before any queries // ES sends FsInn packets for callsigns such as ACCGER1, which are hard to distinguish @@ -854,13 +856,15 @@ namespace swift::core void CAirspaceMonitor::onIcaoCodesReceived(const CCallsign &callsign, const QString &aircraftIcaoDesignator, const QString &airlineIcaoDesignator, const QString &livery) { - // TODO TZ remove when testing is done + // TODO TZ remove logmessage when testing is done + // #SBDAL483:BER636:PI:GEN:EQUIPMENT=B738:AIRLINE=DAL:LIVERY=swift_l1855a1787m13853 CLogMessage(this).info(u"CAirspaceMonitor::onIcaoCodesReceived CHECK:" u"callsign %1 " u"aircraftIcaoDesignator %2 " u"airlineIcaoDesignator %3 " u"livery %4 ") << callsign << aircraftIcaoDesignator << airlineIcaoDesignator << livery; + // End TODO TZ Q_ASSERT_X(CThreadUtils::isInThisThread(this), Q_FUNC_INFO, "not in main thread"); if (!this->isConnectedAndNotShuttingDown()) { return; } diff --git a/src/gui/components/dbownmodelscomponent.cpp b/src/gui/components/dbownmodelscomponent.cpp index 3ab117f419..6da6e9560e 100644 --- a/src/gui/components/dbownmodelscomponent.cpp +++ b/src/gui/components/dbownmodelscomponent.cpp @@ -344,7 +344,8 @@ namespace swift::gui::components Q_UNUSED(modelDirectories); using namespace std::chrono_literals; - const CStatusMessage msg = CLogMessage(this).info(u"Start loading models for %1") << simulator.toQString(); + const CStatusMessage msg = CLogMessage(this).info(u"Triiger loading models for %1 from SimConnect") + << simulator.toQString(); this->showOverlayHTMLMessage(msg, 2s); return; @@ -530,11 +531,10 @@ namespace swift::gui::components IAircraftModelLoader::LoadMode mode, const QStringList &modelDirectories) { - // At this point, we switch how the models should be loaded: SimConnect or classic file search - if (simulator.isMSFS2024()) - this->loadInstalledModelsSimConnect(simulator, mode, modelDirectories); - else - this->loadInstalledModels(simulator, mode, modelDirectories); + // TODO TZ add SimConnect loading + if (simulator.isMSFS2024()) this->loadInstalledModelsSimConnect(simulator, mode, modelDirectories); + + this->loadInstalledModels(simulator, mode, modelDirectories); } void CDbOwnModelsComponent::requestSimulatorModelsWithCacheInBackground(const CSimulatorInfo &simulator) diff --git a/src/gui/models/aircraftmodellistmodel.cpp b/src/gui/models/aircraftmodellistmodel.cpp index 5645007034..ababff5a81 100644 --- a/src/gui/models/aircraftmodellistmodel.cpp +++ b/src/gui/models/aircraftmodellistmodel.cpp @@ -46,10 +46,7 @@ namespace swift::gui::models { case NotSet: case OwnAircraftModelClient: - // m_columns.addColumn(CColumn::standardString("model", { CAircraftModel::IndexModelString })); - m_columns.addColumn(CColumn::standardString("model", { CAircraftModel::IndexShortModelString })); - - m_columns.addColumn(CColumn::standardString("liverypart", CAircraftModel::IndexModelLivery)); + m_columns.addColumn(CColumn::standardString("model", { CAircraftModel::IndexModelString })); m_columns.addColumn( CColumn("DB", "DB metadata", CAircraftModel::IndexDatabaseIcon, new CPixmapFormatter())); m_columns.addColumn( @@ -86,9 +83,7 @@ namespace swift::gui::models case OwnAircraftModelMappingTool: case StashModel: - m_columns.addColumn(CColumn::standardString("model", CAircraftModel::IndexShortModelString)); - - m_columns.addColumn(CColumn::standardString("liverypart", CAircraftModel::IndexModelLivery)); + m_columns.addColumn(CColumn::standardString("model", { CAircraftModel::IndexModelString })); m_columns.addColumn( CColumn("DB", "DB metadata", CAircraftModel::IndexDatabaseIcon, new CPixmapFormatter())); if (mode == StashModel) diff --git a/src/misc/simulation/aircraftmodel.cpp b/src/misc/simulation/aircraftmodel.cpp index cc69cf7739..9b6c04ffbf 100644 --- a/src/misc/simulation/aircraftmodel.cpp +++ b/src/misc/simulation/aircraftmodel.cpp @@ -284,8 +284,6 @@ namespace swift::misc::simulation case IndexLivery: return m_livery.propertyByIndex(index.copyFrontRemoved()); case IndexCallsign: return m_callsign.propertyByIndex(index.copyFrontRemoved()); case IndexMembersDbStatus: return this->getMembersDbStatus(); - case IndexModelLivery: return QVariant(m_modelLivery); - case IndexShortModelString: return QVariant(getShortModelString()); default: return CValueObject::propertyByIndex(index); } } diff --git a/src/misc/simulation/aircraftmodel.h b/src/misc/simulation/aircraftmodel.h index 04066c8866..828b092dba 100644 --- a/src/misc/simulation/aircraftmodel.h +++ b/src/misc/simulation/aircraftmodel.h @@ -127,8 +127,6 @@ namespace swift::misc IndexModelModeAsIcon, IndexHasQueriedModelString, IndexMembersDbStatus, - IndexModelLivery, // MSFS2024 - IndexShortModelString, }; //! \copydoc swift::misc::CValueObject::registerMetadata diff --git a/src/misc/simulation/aircraftmodelloader.cpp b/src/misc/simulation/aircraftmodelloader.cpp index a5a11fb8be..e25b9743e6 100644 --- a/src/misc/simulation/aircraftmodelloader.cpp +++ b/src/misc/simulation/aircraftmodelloader.cpp @@ -131,28 +131,28 @@ namespace swift::misc::simulation return; } + // TODO TZ QStringList modelDirs = { "", "" }; - if (simulator.isMSFS2024()) + // if (simulator.isMSFS2024()) + //{ + // emit this->loadingFinished(m_loadingMessages, simulator, LoadingSkipped); + // return; + // } + // else + //{ + // really load from disk? + modelDirs = this->getInitializedModelDirectories(modelDirectories, simulator); + if (m_skipLoadingEmptyModelDir && modelDirs.isEmpty()) { + const CStatusMessage status = CStatusMessage(this, CStatusMessage::SeverityWarning, + u"Empty or not existing '%1' directory '%2', skipping read") + << simulator.toQString() << modelDirectories.join(", "); + m_loadingMessages.push_back(status); + m_loadingMessages.freezeOrder(); emit this->loadingFinished(m_loadingMessages, simulator, LoadingSkipped); return; } - else - { - // really load from disk? - modelDirs = this->getInitializedModelDirectories(modelDirectories, simulator); - if (m_skipLoadingEmptyModelDir && modelDirs.isEmpty()) - { - const CStatusMessage status = - CStatusMessage(this, CStatusMessage::SeverityWarning, - u"Empty or not existing '%1' directory '%2', skipping read") - << simulator.toQString() << modelDirectories.join(", "); - m_loadingMessages.push_back(status); - m_loadingMessages.freezeOrder(); - emit this->loadingFinished(m_loadingMessages, simulator, LoadingSkipped); - return; - } - } + //} this->setObjectInfo(simulator); this->startLoadingFromDisk(mode, modelConsolidation, modelDirs); diff --git a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp index 7e1d45fe23..933e5c00f1 100644 --- a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp +++ b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp @@ -444,9 +444,9 @@ namespace swift::simplugin::msfs2024common hr += SimConnect_EnumerateSimObjectsAndLiveries(hSimConnect, CSimConnectDefinitions::REQUEST_AIRPLANE, SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT); hr += SimConnect_EnumerateSimObjectsAndLiveries(hSimConnect, CSimConnectDefinitions::REQUEST_HELICOPTER, - SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT); + SIMCONNECT_SIMOBJECT_TYPE_HELICOPTER); // hr += SimConnect_EnumerateSimObjectsAndLiveries(hSimConnect, CSimConnectDefinitions::REQUEST_HOT_AIR, - // SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT); + // SIMCONNECT_SIMOBJECT_TYPE_HOT_AIR_BALLOON); if (isFailure(hr)) { diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp index 52e2f4be51..055f24b3a5 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp @@ -448,11 +448,18 @@ namespace swift::simplugin::msfs2024common const CSpecializedSimulatorSettings settings = this->getSimulatorSettings(); CSimulatorSettings m_generic = settings.getGenericSettings(); QStringList excludePatterns = m_generic.getModelExcludeDirectoryPatterns(); + QStringList filterList = m_generic.getModelDirectories(); bool gui_application = true; + bool useFilterList = true; + bool matchFilter = false; + QString guiName = sGui->getApplicationName(); if (guiName.contains("mapping")) gui_application = false; + const CAircraftMatcherSetup setup = m_matchingSettings.get(); + bool skipExcluded = setup.getMatchingMode().testFlag(CAircraftMatcherSetup::ExcludeNoExcluded); + CAircraftModelList newModels; for (int i = 0; i < static_cast(vSimObjectsAndLiveries.size()); ++i) @@ -463,6 +470,9 @@ namespace swift::simplugin::msfs2024common CAircraftModel modelFromDb = sGui->getWebDataServices()->getModelForModelString(modelLivery.szSimObjectCombinedTitle.trimmed()); + // model is marked as excluded in the database, so skip it + if (modelFromDb.getModelMode() == CAircraftModel::Exclude && skipExcluded && gui_application) { continue; } + // If the model is in the database, there is a DbKey int modelkey = modelFromDb.getDbKey(); if (modelkey) model = modelFromDb; // copy all data from db @@ -487,6 +497,27 @@ namespace swift::simplugin::msfs2024common } if (excluded) continue; // skip adding this model + if (useFilterList) + { + matchFilter = false; + for (const QString &rawFilter : filterList) + { + if (rawFilter.trimmed().contains("*")) + { + // wildcard found, disable filter list + useFilterList = false; + continue; + } + const QString filter = rawFilter.trimmed(); + if (model.getModelString().contains(filter, Qt::CaseInsensitive)) + { + matchFilter = true; + break; + } + } + } + if (useFilterList && !matchFilter) continue; // skip adding this model + newModels.replaceOrAddModelWithString(model, Qt::CaseInsensitive); } @@ -507,7 +538,7 @@ namespace swift::simplugin::msfs2024common bool givenDistributorsOnly = false; bool dbDataOnly = false; bool dbIcaoOnly = false; - bool incremnental = true; + bool incremnental = false; bool sortByDistributor = true; bool consolidateWithDb = false; bool ShowAllInstalledModells = true; // msfs20424 always show all installed models diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.h b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h index 8bc491bce4..fe4954968a 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024common.h +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h @@ -29,6 +29,7 @@ #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" @@ -742,6 +743,10 @@ namespace swift::simplugin::msfs2024common //! Simulator info swift::misc::simulation::CSimulatorInfo m_simulatorInfo; + swift::misc::CSetting m_matchingSettings { + this + }; //!< settings + public: //! @{ //! Offsets From dbe7bf69fb81a32b102969d5e2d5b1756b6063bd Mon Sep 17 00:00:00 2001 From: tzobler Date: Tue, 11 Nov 2025 16:16:18 +0100 Subject: [PATCH 5/8] refactor: Remove TerrainProbe from msfs2024 code --- src/core/airspacemonitor.cpp | 16 +- .../msfs2024/simconnectobjectmsfs2024.cpp | 59 +--- .../msfs2024/simconnectobjectmsfs2024.h | 10 - .../msfs2024/simulatormsfs2024common.cpp | 287 ++++-------------- .../msfs2024/simulatormsfs2024common.h | 66 +--- .../simulatormsfs2024simconnectproc.cpp | 36 --- 6 files changed, 88 insertions(+), 386 deletions(-) diff --git a/src/core/airspacemonitor.cpp b/src/core/airspacemonitor.cpp index 2251acecdd..afc0af21e8 100644 --- a/src/core/airspacemonitor.cpp +++ b/src/core/airspacemonitor.cpp @@ -549,6 +549,12 @@ namespace swift::core if (!this->isConnectedAndNotShuttingDown()) { return; } Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign"); + // TODO TZ remove when testing is done + CLogMessage(this).info(u"CAirspaceMonitor::sendReadyForModelMatching " + u"callsign %1 ") + << callsign; + // TODO remove + // set flag and init ts Readiness &readiness = this->addMatchingReadinessFlag(callsign, rf); @@ -769,12 +775,15 @@ namespace swift::core } } + // for request + // #SBBER750:DAL483:FSIPIR:0:BER:A320:::::L2J:PMDG 737-800 AIRBERLIN (D-ABKM) + // and also for information + // #SBFSC751 : BER636 : FSIPI : 0 ::EC35:: :: : H2T : AIRBUS H135 NORSK LUFTAMBULANSE void CAirspaceMonitor::onCustomFSInnPacketReceived(const CCallsign &callsign, const QString &airlineIcaoDesignator, const QString &aircraftIcaoDesignator, const QString &combinedAircraftType, const QString &modelString) { // TODO TZ remove when testing is done - // #SBBER750:DAL483:FSIPIR:0:BER:A320:::::L2J:PMDG 737-800 AIRBERLIN (D-ABKM) CLogMessage(this).info(u"CAirspaceMonitor::onCustomFSInnPacketReceived CHECK:" u"callsign %1 " u"airlineIcaoDesignator %2 " @@ -853,11 +862,11 @@ namespace swift::core } } + // #SBDAL483:BER636:PI:GEN:EQUIPMENT=B738:AIRLINE=DAL:LIVERY=swift_l1855a1787m13853 void CAirspaceMonitor::onIcaoCodesReceived(const CCallsign &callsign, const QString &aircraftIcaoDesignator, const QString &airlineIcaoDesignator, const QString &livery) { // TODO TZ remove logmessage when testing is done - // #SBDAL483:BER636:PI:GEN:EQUIPMENT=B738:AIRLINE=DAL:LIVERY=swift_l1855a1787m13853 CLogMessage(this).info(u"CAirspaceMonitor::onIcaoCodesReceived CHECK:" u"callsign %1 " u"aircraftIcaoDesignator %2 " @@ -888,6 +897,8 @@ namespace swift::core const CSimulatedAircraft aircraft = this->addOrUpdateAircraftInRange( callsign, aircraftIcaoDesignator, airlineIcaoDesignator, livery, client.getQueriedModelString(), CAircraftModel::TypeQueriedFromNetwork, pReverseLookupMessages); + + // we do not change manually assigned models if (aircraft.getModel().getModelType() != CAircraftModel::TypeManuallySet) { this->addReverseLookupMessages(callsign, reverseLookupMessages); @@ -1211,6 +1222,7 @@ namespace swift::core u"incomming modelType %4 ") << aircraft.getModelType() << callsign.toQString() << aircraftIcao << modelType; + // we do not change manually assigned models if (!aircraft.getModel().hasValidDbKey() && aircraft.getModelType() != CAircraftModel::TypeManuallySet) { diff --git a/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.cpp b/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.cpp index 1d2251fe5b..77f20d06f5 100644 --- a/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.cpp +++ b/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.cpp @@ -34,7 +34,7 @@ namespace swift::simplugin::msfs2024common setupProvider, remoteAircraftProvider, logger)) { this->resetCameraPositions(); - m_type = aircraft.isTerrainProbe() ? TerrainProbe : AircraftNonAtc; + m_type = AircraftNonAtc; m_interpolator->initCorrespondingModel(aircraft.getModel()); m_callsignByteArray = aircraft.getCallsignAsString().toLatin1(); } @@ -43,7 +43,7 @@ namespace swift::simplugin::msfs2024common { m_aircraft = aircraft; m_callsignByteArray = aircraft.getCallsignAsString().toLatin1(); - m_type = aircraft.isTerrainProbe() ? TerrainProbe : AircraftNonAtc; + m_type = AircraftNonAtc; } void CSimConnectObject::setAircraftModelString(const QString &modelString) @@ -78,7 +78,6 @@ namespace swift::simplugin::msfs2024common DWORD os = 0; switch (this->getType()) { - case TerrainProbe: os = static_cast(CSimulatorMsfs2024::offsetSimObjTerrainProbe(offset)); break; case AircraftNonAtc: case AircraftSimulatedObject: default: os = static_cast(CSimulatorMsfs2024::offsetSimObjAircraft(offset)); break; @@ -233,7 +232,6 @@ namespace swift::simplugin::msfs2024common CSimConnectObject::SimObjectType CSimConnectObject::requestIdToType(DWORD requestId) { - if (CSimulatorMsfs2024::isRequestForSimObjTerrainProbe(requestId)) { return TerrainProbe; } if (CSimulatorMsfs2024::isRequestForSimObjAircraft(requestId)) { return AircraftNonAtc; } Q_ASSERT_X(false, Q_FUNC_INFO, "Wrong range"); return AircraftNonAtc; @@ -243,13 +241,12 @@ namespace swift::simplugin::msfs2024common { static const QString a1("aircraft (non ATC)"); static const QString a2("aircraft (sim.object)"); - static const QString p("probe"); + // static const QString p("probe"); static const QString u("unknown"); switch (type) { case AircraftNonAtc: return a1; case AircraftSimulatedObject: return a2; - case TerrainProbe: return p; default: break; } return u; @@ -296,6 +293,7 @@ namespace swift::simplugin::msfs2024common return this->getSimObjectForObjectId(objectId).getCallsign(); } + // TODO TZ optimize? CCallsignSet CSimConnectObjects::getAllCallsigns(bool withoutProbes) const { if (this->isEmpty()) { return CCallsignSet(); } @@ -308,6 +306,7 @@ namespace swift::simplugin::msfs2024common return callsigns; } + // TODO TZ optimize? QStringList CSimConnectObjects::getAllCallsignStrings(bool sorted, bool withoutProbes) const { return this->getAllCallsigns(withoutProbes).getCallsignStrings(sorted); @@ -382,17 +381,17 @@ namespace swift::simplugin::msfs2024common return c > 0; } - int CSimConnectObjects::removeAllProbes() - { - const QList probes = this->getProbes(); - int c = 0; - for (const CSimConnectObject &probe : probes) - { - this->remove(probe.getCallsign()); - c++; - } - return c; - } + // int CSimConnectObjects::removeAllProbes() + //{ + // const QList probes = this->getProbes(); + // int c = 0; + // for (const CSimConnectObject &probe : probes) + // { + // this->remove(probe.getCallsign()); + // c++; + // } + // return c; + // } bool CSimConnectObjects::containsPendingAdded() const { @@ -479,32 +478,6 @@ namespace swift::simplugin::msfs2024common return l; } - CSimConnectObject CSimConnectObjects::getNotPendingProbe() const - { - for (const CSimConnectObject &simObject : *this) - { - if (simObject.getType() == CSimConnectObject::TerrainProbe && !simObject.isPending()) { return simObject; } - } - return CSimConnectObject(); - } - - CSimConnectObject CSimConnectObjects::getOldestNotPendingProbe() const - { - CSimConnectObject oldestProbe; - for (const CSimConnectObject &simObject : *this) - { - if (simObject.getType() == CSimConnectObject::TerrainProbe && !simObject.isPending()) - { - if (!oldestProbe.hasCreatedTimestamp() || - oldestProbe.getCreatedTimestamp() > simObject.getCreatedTimestamp()) - { - oldestProbe = simObject; - } - } - } - return oldestProbe; - } - bool CSimConnectObjects::containsType(CSimConnectObject::SimObjectType type) const { for (const CSimConnectObject &simObject : *this) diff --git a/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.h b/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.h index 6843c57e77..b94048c252 100644 --- a/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.h +++ b/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.h @@ -27,7 +27,6 @@ namespace swift::simplugin::msfs2024common { AircraftNonAtc, AircraftSimulatedObject, - TerrainProbe, AllTypes }; @@ -80,9 +79,6 @@ namespace swift::simplugin::msfs2024common //! Aircraft NON ATC? bool isAircraftNonAtc() const { return this->getType() == AircraftNonAtc; } - //! Probe? - bool isTerrainProbe() const { return this->getType() == TerrainProbe; } - //! Set the type void setType(SimObjectType type) { m_type = type; } @@ -424,9 +420,6 @@ namespace swift::simplugin::msfs2024common //! Get by type QList getByType(CSimConnectObject::SimObjectType type) const; - //! All probes - QList getProbes() const { return this->getByType(CSimConnectObject::TerrainProbe); } - //! All aircraft QList getAircraft() const; @@ -439,9 +432,6 @@ namespace swift::simplugin::msfs2024common //! Contains object of type bool containsType(CSimConnectObject::SimObjectType type) const; - //! Probe? - bool containsProbe() const { return this->containsType(CSimConnectObject::TerrainProbe); } - //! Aircraft? bool containsAircraft() const; }; diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp index 055f24b3a5..2a76dbc2ef 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp @@ -343,34 +343,6 @@ namespace swift::simplugin::msfs2024common .arg(m_requestSimObjectDataCount); } - bool CSimulatorMsfs2024::requestElevation(const ICoordinateGeodetic &reference, const CCallsign &aircraftCallsign) - { - // this is the 32bit FSX version, the P3D x64 is overridden! - - if (this->isShuttingDownOrDisconnected()) { return false; } - if (!this->isUsingFsxTerrainProbe()) { return false; } - if (reference.isNull()) { return false; } - const CSimConnectObject simObject = m_simConnectObjects.getOldestNotPendingProbe(); // probes round robin - if (!simObject.isConfirmedAdded()) { return false; } - m_simConnectObjects[simObject.getCallsign()].resetTimestampToNow(); // mark probe as just used - - CCoordinateGeodetic pos(reference); - pos.setGeodeticHeight(terrainProbeAltitude()); - - SIMCONNECT_DATA_INITPOSITION position = this->coordinateToFsxPosition(pos); - const HRESULT hr = this->logAndTraceSendId( - SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetPosition, - simObject.getObjectId(), 0, 0, sizeof(SIMCONNECT_DATA_INITPOSITION), - &position), - simObject, "Cannot request AI elevation", Q_FUNC_INFO, "SimConnect_SetDataOnSimObject"); - - if (isFailure(hr)) { return false; } - - const bool ok = this->requestTerrainProbeData(simObject, aircraftCallsign); - if (ok) { emit this->requestedElevation(aircraftCallsign); } - return ok; - } - void CSimulatorMsfs2024::CacheSimObjectAndLiveries(const SIMCONNECT_RECV_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST *msg) { for (unsigned i = 0; i < msg->dwArraySize; ++i) @@ -722,10 +694,6 @@ namespace swift::simplugin::msfs2024common { DWORD v = static_cast(CSimConnectDefinitions::SimObjectEndMarker); if (isRequestForSimObjAircraft(requestId)) { v = (requestId - RequestSimObjAircraftStart) / MaxSimObjAircraft; } - else if (isRequestForSimObjTerrainProbe(requestId)) - { - v = (requestId - RequestSimObjTerrainProbeStart) / MaxSimObjProbes; - } Q_ASSERT_X(v <= CSimConnectDefinitions::SimObjectEndMarker, Q_FUNC_INFO, "Invalid value"); return static_cast(v); } @@ -849,13 +817,6 @@ namespace swift::simplugin::msfs2024common return id; } - SIMCONNECT_DATA_REQUEST_ID CSimulatorMsfs2024::obtainRequestIdForSimObjTerrainProbe() - { - const SIMCONNECT_DATA_REQUEST_ID id = m_requestIdSimObjTerrainProbe++; - if (id > RequestSimObjTerrainProbeEnd) { m_requestIdSimObjTerrainProbe = RequestSimObjTerrainProbeStart; } - return id; - } - bool CSimulatorMsfs2024::releaseAIControl(const CSimConnectObject &simObject, SIMCONNECT_DATA_REQUEST_ID requestId) { const SIMCONNECT_OBJECT_ID objectId = simObject.getObjectId(); @@ -1096,15 +1057,10 @@ namespace swift::simplugin::msfs2024common } else { --m_skipCockpitUpdateCycles; } + // TODO TZ check if we need to update terrain probes // slower updates if (m_ownAircraftUpdateCycles % 10 == 0) { - // init terrain probes here has the advantage we can also switch it on/off at runtime - if (m_useFsxTerrainProbe && !m_initFsxTerrainProbes) - { - this->physicallyInitAITerrainProbes(position, 2); // init probe - } - // SB3 offsets updating m_simulatorInternals.setValue(QStringLiteral("fsx/sb3"), boolToEnabledDisabled(m_useSbOffsets)); m_simulatorInternals.setValue(QStringLiteral("fsx/sb3packets"), m_useSbOffsets ? @@ -1297,11 +1253,6 @@ namespace swift::simplugin::msfs2024common void CSimulatorMsfs2024::verifyAddedRemoteAircraft(const CSimulatedAircraft &remoteAircraftIn) { if (this->isShuttingDownOrDisconnected()) { return; } - if (remoteAircraftIn.isTerrainProbe()) - { - this->verifyAddedTerrainProbe(remoteAircraftIn); - return; - } CStatusMessage msg; CSimulatedAircraft remoteAircraft = remoteAircraftIn; @@ -1524,36 +1475,6 @@ namespace swift::simplugin::msfs2024common return r; } - void CSimulatorMsfs2024::verifyAddedTerrainProbe(const CSimulatedAircraft &remoteAircraftIn) - { - bool verified = false; - CCallsign cs; - - // no simObject reference outside that block, because it will be deleted - { - CSimConnectObject &simObject = m_simConnectObjects[remoteAircraftIn.getCallsign()]; - simObject.setConfirmedAdded(true); // terrain probe - simObject.resetTimestampToNow(); - cs = simObject.getCallsign(); - CLogMessage(this).info(u"Probe: '%1' '%2' confirmed, %3") - << simObject.getCallsignAsString() << simObject.getAircraftModelString() << simObject.toQString(); - - // fails for probe - // SIMCONNECT_DATA_REQUEST_ID requestId = this->obtainRequestIdForSimObjTerrainProbe(); - // verified = this->releaseAIControl(simObject, requestId); // release probe - verified = true; - } - - if (!verified) // cppcheck-suppress knownConditionTrueFalse - { - CLogMessage(this).info(u"Disable probes: '%1' failed to relase control") << cs.asString(); - m_useFsxTerrainProbe = false; - } - - // trigger new adding from pending if any - if (!m_addPendingAircraft.isEmpty()) { this->addPendingAircraftAfterAdded(); } - } - void CSimulatorMsfs2024::timerBasedObjectAddOrRemove() { this->addPendingAircraft(AddByTimer); @@ -1576,10 +1497,6 @@ namespace swift::simplugin::msfs2024common { SWIFT_VERIFY_X(pendingSimObj.hasCallsign(), Q_FUNC_INFO, "missing callsign"); if (!pendingSimObj.hasCallsign()) { continue; } - if (pendingSimObj.isTerrainProbe() || aircraftCallsignsInRange.contains(pendingSimObj.getCallsign())) - { - toBeAddedAircraft.push_back(pendingSimObj.getAircraft()); - } else { toBeRemovedCallsigns.push_back(pendingSimObj.getCallsign()); } } @@ -1597,7 +1514,6 @@ namespace swift::simplugin::msfs2024common const QPointer myself(this); QTimer::singleShot(100, this, [=] { if (!myself) { return; } - if (this->isShuttingDownDisconnectedOrNoAircraft(nextPendingAircraft.isTerrainProbe())) { return; } this->physicallyAddRemoteAircraftImpl(nextPendingAircraft, mode, oldestSimObject); }); } @@ -1780,12 +1696,12 @@ namespace swift::simplugin::msfs2024common CSimpleCommandParser::registerCommand({ ".drv sblog on|off", "SB offsets logging on|off" }); } - CCallsign CSimulatorMsfs2024::getCallsignForPendingProbeRequests(DWORD requestId, bool remove) - { - const CCallsign cs = m_pendingProbeRequests.value(requestId); - if (remove) { m_pendingProbeRequests.remove(requestId); } - return cs; - } + // CCallsign CSimulatorMsfs2024::getCallsignForPendingProbeRequests(DWORD requestId, bool remove) + //{ + // const CCallsign cs = m_pendingProbeRequests.value(requestId); + // if (remove) { m_pendingProbeRequests.remove(requestId); } + // return cs; + // } const QString &CSimulatorMsfs2024::modeToString(CSimulatorMsfs2024::AircraftAddMode mode) { @@ -1870,7 +1786,6 @@ namespace swift::simplugin::msfs2024common const CSimConnectObject &correspondingSimObject) { const CCallsign callsign(newRemoteAircraft.getCallsign()); - const bool probe = newRemoteAircraft.isTerrainProbe(); // entry checks Q_ASSERT_X(CThreadUtils::isInThisThread(this), Q_FUNC_INFO, "thread"); @@ -1996,7 +1911,8 @@ namespace swift::simplugin::msfs2024common const CSimConnectObject removedPendingObj = this->removeFromAddPendingAndAddAgainAircraft(callsign); // create AI after crosschecking it - if (!probe && !this->isAircraftInRangeOrTestMode(callsign)) + // if (!probe && !this->isAircraftInRangeOrTestMode(callsign)) + if (!this->isAircraftInRangeOrTestMode(callsign)) { CLogMessage(this).info(u"Skipping adding of '%1' since it is no longer in range") << callsign.asString(); return false; @@ -2007,10 +1923,8 @@ namespace swift::simplugin::msfs2024common this->getInterpolationSetupConsolidated(callsign, true); const bool sendGround = setup.isSendingGndFlagToSimulator(); - // FSX/P3D adding bool adding = false; // will be added flag - const SIMCONNECT_DATA_REQUEST_ID requestId = - probe ? this->obtainRequestIdForSimObjTerrainProbe() : this->obtainRequestIdForSimObjAircraft(); + const SIMCONNECT_DATA_REQUEST_ID requestId = this->obtainRequestIdForSimObjAircraft(); // Initial situation, if possible from interpolation CAircraftSituation initialSituation = newRemoteAircraft.getSituation(); // default @@ -2045,43 +1959,31 @@ namespace swift::simplugin::msfs2024common const QByteArray modelStringBa = toFsxChar(modelString).trimmed(); const QByteArray modelLiveryBa = toFsxChar(modelLiveryString).trimmed(); - const QByteArray csBa = toFsxChar(callsign.toQString().left(12)); CSimConnectObject::SimObjectType type = CSimConnectObject::AircraftNonAtc; HRESULT hr = S_OK; - if (probe) + if (this->isAddingAsSimulatedObjectEnabled() && correspondingSimObject.hasCallsign() && + correspondingSimObject.getAddingExceptions() > 0 && + correspondingSimObject.getType() == CSimConnectObject::AircraftNonAtc) { + CStatusMessage(this).warning( + u"Model '%1' for '%2' failed %1 time(s) before, using AICreateSimulatedObject now") + << newRemoteAircraft.getModelString() << callsign.toQString(); + hr = SimConnect_AICreateNonATCAircraft_EX1(m_hSimConnect, modelStringBa.constData(), modelLiveryBa.constData(), csBa.constData(), initialPosition, requestId); - type = CSimConnectObject::TerrainProbe; + type = CSimConnectObject::AircraftSimulatedObject; } else { - if (this->isAddingAsSimulatedObjectEnabled() && correspondingSimObject.hasCallsign() && - correspondingSimObject.getAddingExceptions() > 0 && - correspondingSimObject.getType() == CSimConnectObject::AircraftNonAtc) - { - CStatusMessage(this).warning( - u"Model '%1' for '%2' failed %1 time(s) before, using AICreateSimulatedObject now") - << newRemoteAircraft.getModelString() << callsign.toQString(); - - hr = SimConnect_AICreateNonATCAircraft_EX1(m_hSimConnect, modelStringBa.constData(), - modelLiveryBa.constData(), csBa.constData(), initialPosition, - requestId); - - type = CSimConnectObject::AircraftSimulatedObject; - } - else - { - hr = SimConnect_AICreateNonATCAircraft_EX1(m_hSimConnect, modelStringBa.constData(), - modelLiveryBa.constData(), csBa.constData(), initialPosition, - requestId); + hr = SimConnect_AICreateNonATCAircraft_EX1(m_hSimConnect, modelStringBa.constData(), + modelLiveryBa.constData(), csBa.constData(), initialPosition, + requestId); - type = CSimConnectObject::AircraftNonAtc; - } + type = CSimConnectObject::AircraftNonAtc; } if (!underflowStatus.isEmpty()) @@ -2110,52 +2012,6 @@ namespace swift::simplugin::msfs2024common return adding; } - bool CSimulatorMsfs2024::physicallyAddAITerrainProbe(const ICoordinateGeodetic &coordinate, int number) - { - if (coordinate.isNull()) { return false; } - if (!this->isUsingFsxTerrainProbe()) { return false; } - Q_ASSERT_X(CThreadUtils::isInThisThread(this), Q_FUNC_INFO, "thread"); - - // static const QString modelString("OrcaWhale"); - // static const QString modelString("Water Drop"); // not working on P3Dx86/FSX, no requests on that id - // possible static const QString modelString("A321ACA"); static const QString - // modelString("AI_Tracker_Object_0"); static const QString modelString("Piper Cub"); // P3Dv86 works as - // nonATC/SimulatedObject static const QString modelString("Discovery Spaceshuttle"); // P3Dx86 works as - // nonATC/SimulatedObject - static const QString modelString("swiftTerrainProbe0"); - static const QString pseudoCallsign("PROBE%1"); // max 12 chars - static const CCountry ctry("SW", "SWIFT"); - static const CAirlineIcaoCode swiftAirline("SWI", "swift probe", ctry, "SWIFT", false, false); - static const CLivery swiftLivery(CLivery::getStandardCode(swiftAirline), swiftAirline, "swift probe"); - - const CCallsign cs(pseudoCallsign.arg(number)); - const CAircraftModel model(modelString, CAircraftModel::TypeTerrainProbe, QStringLiteral("swift terrain probe"), - CAircraftIcaoCode::unassignedIcao(), swiftLivery); - CAircraftSituation situation(cs, coordinate); - situation.setAltitude(terrainProbeAltitude()); - situation.setZeroPBH(); - const CSimulatedAircraft pseudoAircraft(cs, model, CUser("123456", "swift", cs), situation); - return this->physicallyAddRemoteAircraftImpl(pseudoAircraft, ExternalCall); - } - - int CSimulatorMsfs2024::physicallyInitAITerrainProbes(const ICoordinateGeodetic &coordinate, int number) - { - if (number < 1) { return 0; } - if (m_initFsxTerrainProbes) { return m_addedProbes; } - m_initFsxTerrainProbes = true; // no multiple inits - this->triggerAutoTraceSendId(); - - int c = 0; - for (int n = 0; n < number; ++n) - { - if (this->physicallyAddAITerrainProbe(coordinate, n)) { c++; } - } - - CLogMessage(this).info(u"Adding %1 FSX terrain probes") << number; - m_addedProbes = c; - return c; - } - bool CSimulatorMsfs2024::physicallyRemoveRemoteAircraft(const CCallsign &callsign) { // only remove from sim @@ -2169,7 +2025,6 @@ namespace swift::simplugin::msfs2024common if (!m_simConnectObjects.contains(callsign)) { return false; } // already fully removed or not yet added CSimConnectObject &simObject = m_simConnectObjects[callsign]; if (simObject.isPendingRemoved()) { return true; } - if (simObject.isTerrainProbe()) { return false; } // check for pending objects m_addPendingAircraft.remove(callsign); // just in case still in list of pending aircraft @@ -2543,8 +2398,7 @@ namespace swift::simplugin::msfs2024common bool CSimulatorMsfs2024::sendRemoteAircraftAtcDataToSimulator(const CSimConnectObject &simObject) { if (!simObject.isReadyToSend()) { return false; } - if (simObject.isTerrainProbe()) { return false; } - // if (simObject.getType() != CSimConnectObject::AircraftNonAtc) { return false; } // otherwise errors + if (simObject.getType() != CSimConnectObject::AircraftNonAtc) { return false; } // otherwise errors const DWORD objectId = simObject.getObjectId(); const bool traceId = this->isTracingSendId(); @@ -2813,23 +2667,6 @@ namespace swift::simplugin::msfs2024common return false; } - bool CSimulatorMsfs2024::requestTerrainProbeData(const CSimConnectObject &simObject, - const CCallsign &aircraftCallsign) - { - static const QString w("Cannot request terrain probe data for id '%1'"); - const SIMCONNECT_DATA_REQUEST_ID requestId = - simObject.getRequestId(CSimConnectDefinitions::SimObjectPositionData); - const DWORD objectId = simObject.getObjectId(); - const HRESULT result = this->logAndTraceSendId( - SimConnect_RequestDataOnSimObject(m_hSimConnect, static_cast(requestId), - CSimConnectDefinitions::DataRemoteAircraftGetPosition, - static_cast(objectId), SIMCONNECT_PERIOD_ONCE), - simObject, w.arg(requestId), Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject"); - const bool ok = isOk(result); - if (ok) { m_pendingProbeRequests.insert(requestId, aircraftCallsign); } - return ok; - } - bool CSimulatorMsfs2024::requestLightsForSimObject(const CSimConnectObject &simObject) { if (!this->isValidSimObjectNotPendingRemoved(simObject)) { return false; } @@ -2908,33 +2745,16 @@ namespace swift::simplugin::msfs2024common m_requestIdSimObjAircraft = static_cast(RequestSimObjAircraftStart); m_dispatchErrors = 0; m_receiveExceptionCount = 0; - m_addedProbes = 0; - m_initFsxTerrainProbes = false; m_sendIdTraces.clear(); } void CSimulatorMsfs2024::clearAllRemoteAircraftData() { - const bool reinitProbe = - m_useFsxTerrainProbe && m_initFsxTerrainProbes; // re-init if enabled and was initialized - this->removeAllProbes(); - // m_addAgainAircraftWhenRemoved cleared below CSimulatorFsCommon::clearAllRemoteAircraftData(); // also removes aircraft m_simConnectObjects.clear(); m_addPendingAircraft.clear(); m_simConnectObjectsPositionAndPartsTraces.clear(); - - if (reinitProbe) - { - // if we are still alive we re-init the probes - QPointer myself(this); - QTimer::singleShot(2000, this, [=] { - // Shutdown or unloaded - if (this->isShuttingDown() || !myself) { return; } - m_initFsxTerrainProbes = false; // probes will re-init - }); - } } void CSimulatorMsfs2024::onOwnModelChanged(const CAircraftModel &newModel) @@ -3033,29 +2853,30 @@ namespace swift::simplugin::msfs2024common return d.arg(trace.sendId).arg(simObject.getObjectId()).arg(simObject.toQString(), trace.comment); } - int CSimulatorMsfs2024::removeAllProbes() - { - if (!m_hSimConnect) { return 0; } // already disconnected - const QList probes = m_simConnectObjects.getProbes(); - - int c = 0; - for (const CSimConnectObject &probeSimObject : probes) - { - if (!probeSimObject.isConfirmedAdded()) { continue; } - const SIMCONNECT_DATA_REQUEST_ID requestId = - probeSimObject.getRequestId(CSimConnectDefinitions::SimObjectRemove); - const HRESULT result = SimConnect_AIRemoveObject( - m_hSimConnect, static_cast(probeSimObject.getObjectId()), requestId); - if (isOk(result)) { c++; } - else - { - CLogMessage(this).warning(u"Removing probe '%1' from simulator failed") << probeSimObject.getObjectId(); - } - } - m_simConnectObjects.removeAllProbes(); - m_pendingProbeRequests.clear(); - return c; - } + // int CSimulatorMsfs2024::removeAllProbes() + //{ + // if (!m_hSimConnect) { return 0; } // already disconnected + // const QList probes = m_simConnectObjects.getProbes(); + + // int c = 0; + // for (const CSimConnectObject &probeSimObject : probes) + // { + // if (!probeSimObject.isConfirmedAdded()) { continue; } + // const SIMCONNECT_DATA_REQUEST_ID requestId = + // probeSimObject.getRequestId(CSimConnectDefinitions::SimObjectRemove); + // const HRESULT result = SimConnect_AIRemoveObject( + // m_hSimConnect, static_cast(probeSimObject.getObjectId()), requestId); + // if (isOk(result)) { c++; } + // else + // { + // CLogMessage(this).warning(u"Removing probe '%1' from simulator failed") << + // probeSimObject.getObjectId(); + // } + // } + // m_simConnectObjects.removeAllProbes(); + // m_pendingProbeRequests.clear(); + // return c; + //} CSimConnectObject CSimulatorMsfs2024::insertNewSimConnectObject(const CSimulatedAircraft &aircraft, DWORD requestId, CSimConnectObject::SimObjectType type, @@ -3092,11 +2913,11 @@ namespace swift::simplugin::msfs2024common return simObject; } - const CAltitude &CSimulatorMsfs2024::terrainProbeAltitude() - { - static const CAltitude alt(50000, CLengthUnit::ft()); - return alt; - } + // const CAltitude &CSimulatorMsfs2024::terrainProbeAltitude() + //{ + // static const CAltitude alt(50000, CLengthUnit::ft()); + // return alt; + // } QString CSimulatorMsfs2024::fsxCharToQString(const char *fsxChar, int size) { @@ -3125,10 +2946,6 @@ namespace swift::simplugin::msfs2024common int end; switch (type) { - case CSimConnectObject::TerrainProbe: - start = RequestSimObjTerrainProbeStart; - end = RequestSimObjTerrainProbeEnd; - break; case CSimConnectObject::AircraftNonAtc: case CSimConnectObject::AircraftSimulatedObject: default: diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.h b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h index fe4954968a..760c62992f 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024common.h +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h @@ -105,9 +105,6 @@ namespace swift::simplugin::msfs2024common CSimConnectObject simObject; //!< CSimConnectObject at the time of the trace QString comment; //!< where sent - //! For probe - bool isForProbe() const { return simObject.getType() == CSimConnectObject::TerrainProbe; } - //! For aircraft bool isForAircraft() const { return simObject.getType() == CSimConnectObject::AircraftNonAtc; } @@ -187,11 +184,11 @@ namespace swift::simplugin::msfs2024common 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; + ////! \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); @@ -214,13 +211,6 @@ namespace swift::simplugin::msfs2024common //! Set tracing on/off void setTractingSendId(bool trace); - //! FSX Terrain probe - //! \remark must be off at P3D v4.2 drivers or later - bool isUsingFsxTerrainProbe() const { return m_useFsxTerrainProbe; } - - //! FSX terrain probe - void setUsingFsxTerrainProbe(bool use) { m_useFsxTerrainProbe = use; } - //! Using the SB offsets? bool isUsingSbOffsetValues() const { return m_useSbOffsets; } @@ -243,17 +233,8 @@ namespace swift::simplugin::msfs2024common return requestId >= RequestSimObjAircraftStart && requestId <= RequestSimObjAircraftRangeEnd; } - //! Request for probe (elevation)? - static bool isRequestForSimObjTerrainProbe(DWORD requestId) - { - return requestId >= RequestSimObjTerrainProbeStart && requestId <= RequestSimObjTerrainProbeRangeEnd; - } - //! Request for any CSimConnectObject? - static bool isRequestForSimConnectObject(DWORD requestId) - { - return isRequestForSimObjAircraft(requestId) || isRequestForSimObjTerrainProbe(requestId); - } + static bool isRequestForSimConnectObject(DWORD requestId) { return isRequestForSimObjAircraft(requestId); } //! Sub request type static CSimConnectDefinitions::SimObjectRequest requestToSimObjectRequest(DWORD requestId); @@ -309,9 +290,6 @@ namespace swift::simplugin::msfs2024common //! Get new request id, overflow safe SIMCONNECT_DATA_REQUEST_ID obtainRequestIdForSimObjAircraft(); - //! Get new request id, overflow safe - SIMCONNECT_DATA_REQUEST_ID obtainRequestIdForSimObjTerrainProbe(); - //! Release AI control //! \remark P3D version is overridden virtual bool releaseAIControl(const CSimConnectObject &simObject, SIMCONNECT_DATA_REQUEST_ID requestId); @@ -388,10 +366,6 @@ namespace swift::simplugin::msfs2024common //!< overriden by specialized P3D function CSimConnectObjects m_simConnectObjects; //!< AI objects and their object and request ids - // probes - bool m_useFsxTerrainProbe = is32bit(); //!< Use FSX Terrain probe? - bool m_initFsxTerrainProbes = false; //!< initialized terrain probes - int m_addedProbes = 0; //!< added probes QMap m_pendingProbeRequests; //!< pending elevation requests: requestId/aircraft callsign @@ -421,14 +395,6 @@ namespace swift::simplugin::msfs2024common AircraftAddMode addMode, const CSimConnectObject &correspondingSimObject = {}); - //! Add AI object for terrain probe - //! \remark experimental - bool physicallyAddAITerrainProbe(const swift::misc::geo::ICoordinateGeodetic &coordinate, int number); - - //! Add number probes (inits the probe objects) - //! \remark experimental - int physicallyInitAITerrainProbes(const swift::misc::geo::ICoordinateGeodetic &coordinate, int number); - //! 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(); @@ -450,9 +416,6 @@ namespace swift::simplugin::msfs2024common //! Logging version of verifyFailedAircraftInfo bool logVerifyFailedAircraftInfo(const CSimConnectObject &simObject) const; - //! Verify the probe - void verifyAddedTerrainProbe(const swift::misc::simulation::CSimulatedAircraft &remoteAircraftIn); - //! Add next aircraft based on timer void timerBasedObjectAddOrRemove(); @@ -586,10 +549,6 @@ namespace swift::simplugin::msfs2024common bool requestPositionDataForSimObject(const CSimConnectObject &simObject, SIMCONNECT_PERIOD period = SIMCONNECT_PERIOD_SECOND); - //! Request data for the terrain probe - bool requestTerrainProbeData(const CSimConnectObject &simObject, - const swift::misc::aviation::CCallsign &aircraftCallsign); - //! Request lights for a CSimConnectObject bool requestLightsForSimObject(const CSimConnectObject &simObject); @@ -655,13 +614,6 @@ namespace swift::simplugin::msfs2024common RequestSimObjAircraftStart - 1 + static_cast(CSimConnectDefinitions::SimObjectEndMarker) * MaxSimObjAircraft; - // -- range for probe data, each probe object will get its own request id and use the offset ranges - static constexpr int RequestSimObjTerrainProbeStart = RequestSimObjAircraftRangeEnd + 1; - static constexpr int RequestSimObjTerrainProbeEnd = RequestSimObjTerrainProbeStart - 1 + MaxSimObjProbes; - static constexpr int RequestSimObjTerrainProbeRangeEnd = - RequestSimObjTerrainProbeStart - 1 + - static_cast(CSimConnectDefinitions::SimObjectEndMarker) * MaxSimObjProbes; - // times static constexpr int AddPendingAircraftIntervalMs = 20 * 1000; static constexpr int DispatchIntervalMs = 10; //!< how often with run the FSX event queue @@ -713,8 +665,6 @@ namespace swift::simplugin::msfs2024common 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 - SIMCONNECT_DATA_REQUEST_ID m_requestIdSimObjTerrainProbe = static_cast( - RequestSimObjTerrainProbeStart); //!< request id, use obtainRequestIdForSimObjTerrainProbe 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 @@ -754,10 +704,6 @@ namespace swift::simplugin::msfs2024common { return MaxSimObjAircraft * static_cast(req); } - static DWORD offsetSimObjTerrainProbe(CSimConnectDefinitions::SimObjectRequest req) - { - return MaxSimObjProbes * static_cast(req); - } //! @} }; diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp index 39cd5e391d..45e338812b 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp @@ -113,11 +113,6 @@ namespace swift::simplugin::msfs2024common Q_UNUSED(removed); CLogMessage(simulatorMsfs2024).warning(u"Adding probe failed: %1 %2") << simObject.getCallsign().asString() << simObject.getAircraftModelString(); - if (simulatorMsfs2024->isUsingFsxTerrainProbe()) - { - CLogMessage(simulatorMsfs2024).warning(u"Disabling terrain probe"); - simulatorMsfs2024->setUsingFsxTerrainProbe(false); - } logGenericExceptionInfo = false; } // aircraft } // valid @@ -366,37 +361,6 @@ namespace swift::simplugin::msfs2024common } } } - else if (CSimulatorMsfs2024::isRequestForSimObjTerrainProbe(requestId)) - { - const CSimConnectObject probeObj = simulatorMsfs2024->getSimObjectForObjectId(objectId); - if (!probeObj.hasValidRequestAndObjectId()) { break; } - Q_ASSERT_X(probeObj.isTerrainProbe(), Q_FUNC_INFO, "No probe"); - const CSimConnectDefinitions::SimObjectRequest subRequest = - CSimulatorMsfs2024::requestToSimObjectRequest(requestId); - - if (subRequest == CSimConnectDefinitions::SimObjectPositionData) - { - static_assert(sizeof(DataDefinitionPosData) == 5 * sizeof(double), - "DataDefinitionRemoteAircraftSimData has an incorrect size."); - const DataDefinitionPosData *probeSimData = - reinterpret_cast(&pObjData->dwData); - // extra check, but ids should be the same - if (objectId == probeObj.getObjectId()) - { - const CCallsign cs = simulatorMsfs2024->m_pendingProbeRequests.value(requestId); - if (cs.isEmpty()) { break; } - simulatorMsfs2024->updateProbeFromSimulator(cs, *probeSimData); - } - } - else - { - if (CBuildConfig::isLocalDeveloperDebugBuild()) - { - CLogMessage(simulatorMsfs2024).error(u"Unknown subrequest (probe): '%1' %2") - << CSimConnectDefinitions::simObjectRequestToString(subRequest) << probeObj.toQString(); - } - } - } // probe } break; // default (SIMCONNECT_RECV_ID_SIMOBJECT_DATA) } From a3d6bb871f40bbe8e0aa260432cbde19effeeb82 Mon Sep 17 00:00:00 2001 From: tzobler Date: Thu, 13 Nov 2025 13:58:36 +0100 Subject: [PATCH 6/8] feat: new lights and number of engines increased to 6 --- src/core/airspacemonitor.cpp | 17 +- src/core/context/contextnetworkimpl.cpp | 4 - src/core/simulator.cpp | 9 - src/gui/components/logincomponent.cpp | 4 +- src/gui/components/mappingcomponent.cpp | 6 - src/gui/editors/aircraftpartsform.cpp | 9 +- src/gui/editors/aircraftpartsform.ui | 32 +- src/gui/models/aircraftmodellistmodel.cpp | 1 - src/misc/CMakeLists.txt | 4 +- src/misc/aviation/aircraftlights.cpp | 40 +- src/misc/aviation/aircraftlights.h | 35 +- src/misc/simulation/aircraftmodelloader.cpp | 2 +- .../msfs2024/aircraftmodelloadermsfs2024.cpp | 4 +- .../msfs2024/simconnectutilities.cpp | 75 ++++ .../simulation/msfs2024/simconnectutilities.h | 204 +++++++++ .../simconnectdatadefinitionmsfs2024.cpp | 33 +- .../simconnectdatadefinitionmsfs2024.h | 21 +- .../simulator/msfs2024/simulatormsfs2024.cpp | 2 +- .../msfs2024/simulatormsfs2024common.cpp | 392 ++++++++++-------- .../msfs2024/simulatormsfs2024common.h | 43 +- .../simulatormsfs2024simconnectproc.cpp | 9 +- src/swiftdata/swiftdataapplication.cpp | 47 +-- 22 files changed, 665 insertions(+), 328 deletions(-) create mode 100644 src/misc/simulation/msfs2024/simconnectutilities.cpp create mode 100644 src/misc/simulation/msfs2024/simconnectutilities.h diff --git a/src/core/airspacemonitor.cpp b/src/core/airspacemonitor.cpp index afc0af21e8..bd350fb8f7 100644 --- a/src/core/airspacemonitor.cpp +++ b/src/core/airspacemonitor.cpp @@ -551,8 +551,8 @@ namespace swift::core // TODO TZ remove when testing is done CLogMessage(this).info(u"CAirspaceMonitor::sendReadyForModelMatching " - u"callsign %1 ") - << callsign; + u"callsign %1 Flag %2 ") + << callsign << rf; // TODO remove // set flag and init ts @@ -1212,17 +1212,7 @@ namespace swift::core const CSimulatedAircraft aircraft = this->getAircraftInRangeForCallsign(callsign); if (aircraft.hasValidCallsign()) { - // TODO TZ at this point we have a poblem if the model has no DB key yet (msfs2024 liveries) - // only if we do not have a DB model yet - // int testType = aircraft.getModelType();1 - CLogMessage(this).info(u"CAirspaceMonitor::addOrUpdateAircraftInRange CHECK:" - u"aircraft.getModelType %1 " - u"callsign %2 " - u"aircraftIcao %3 " - u"incomming modelType %4 ") - << aircraft.getModelType() << callsign.toQString() << aircraftIcao << modelType; - - // we do not change manually assigned models + // we do not change manually assigned models (msfs2024) if (!aircraft.getModel().hasValidDbKey() && aircraft.getModelType() != CAircraftModel::TypeManuallySet) { @@ -1491,6 +1481,7 @@ namespace swift::core this->updateAircraftInRange(callsign, vm); } + // TODO TZ I think, we can remove this method in future, as we have now longer IVAO supported protocols void CAirspaceMonitor::onRevBAircraftConfigReceived(const CCallsign &callsign, const QString &config, qint64 currentOffsetMs) { diff --git a/src/core/context/contextnetworkimpl.cpp b/src/core/context/contextnetworkimpl.cpp index 63ac22a408..894b2f468c 100644 --- a/src/core/context/contextnetworkimpl.cpp +++ b/src/core/context/contextnetworkimpl.cpp @@ -1142,10 +1142,6 @@ namespace swift::core::context if (c) { const CSimulatedAircraft aircraft(this->getAircraftInRangeForCallsign(callsign)); - // TODO TZ - CLogMessage(this).info(u"CContextNetwork::updateAircraftModel model.getModelString %1 model.getModelLivery " - u"%2 model.getModelType %3 aircraft.getModelType '%4'") - << model.getModelString() << model.getModelLivery() << model.getModelType() << aircraft.getModelType(); Q_ASSERT_X(!aircraft.getCallsign().isEmpty(), Q_FUNC_INFO, "missing callsign"); emit this->changedRemoteAircraftModel(aircraft, originator); // update aircraft model diff --git a/src/core/simulator.cpp b/src/core/simulator.cpp index 7af290c344..69bef852f4 100644 --- a/src/core/simulator.cpp +++ b/src/core/simulator.cpp @@ -981,15 +981,6 @@ namespace swift::core bool ISimulator::changeRemoteAircraftEnabled(const CSimulatedAircraft &aircraft) { if (this->isShuttingDown()) { return false; } - - // TODO TZ remove after testing - CLogMessage(this).info(u"ISimulator::changeRemoteAircraftEnabled CHECK:" - u"aircraft.getModelType %1 " - u"aircraft.getModelString %2 " - u"aircraft.getLiveryString %3 ") - << aircraft.getModelType() << aircraft.getModelString() << aircraft.getLiveryString(); - ; - return aircraft.isEnabled() ? this->physicallyAddRemoteAircraft(aircraft) : this->physicallyRemoveRemoteAircraft(aircraft.getCallsign()); } diff --git a/src/gui/components/logincomponent.cpp b/src/gui/components/logincomponent.cpp index 507c3c10a0..d57c0350f2 100644 --- a/src/gui/components/logincomponent.cpp +++ b/src/gui/components/logincomponent.cpp @@ -41,7 +41,7 @@ #include "misc/logmessage.h" #include "misc/network/connectionstatus.h" #include "misc/network/entityflags.h" -// TODO TZ remove afte testing +// TODO TZ remove after testing. it is in another branch already #include "misc/network/server.h" // TODO TZ end remove afte testing #include "misc/network/serverlist.h" @@ -301,7 +301,7 @@ namespace swift::gui::components { if (!m_updatePilotOnServerChanges) { return; } const bool vatsim = this->isVatsimNetworkTabSelected(); - // TODO TZ remove after testing + // TODO TZ remove after testing. it is on another branch already // const CUser user = vatsim ? this->getCurrentVatsimServer().getUser() : server.getUser(); const CUser user = server.getServerType() != CServer::FSDServer ? this->getCurrentVatsimServer().getUser() : server.getUser(); diff --git a/src/gui/components/mappingcomponent.cpp b/src/gui/components/mappingcomponent.cpp index 6ee3695e47..ef92d35e5c 100644 --- a/src/gui/components/mappingcomponent.cpp +++ b/src/gui/components/mappingcomponent.cpp @@ -370,12 +370,6 @@ namespace swift::gui::components { const CAircraftModelList models = sGui->getIContextSimulator()->getModelSetModelsStartingWith(modelString); - // TODO TZ DEBUG only for testing - const CStatusMessage msg = CStatusMessage(this).validationInfo(u"Found: %1 models for %2") - << models.size() << modelString; - this->showOverlayMessage(msg, OverlayMessageMs); - // END testing - if (models.isEmpty()) { const CStatusMessage msg = CStatusMessage(this).validationError(u"No model for title: '%1'") diff --git a/src/gui/editors/aircraftpartsform.cpp b/src/gui/editors/aircraftpartsform.cpp index bbaae96150..09559ba245 100644 --- a/src/gui/editors/aircraftpartsform.cpp +++ b/src/gui/editors/aircraftpartsform.cpp @@ -100,6 +100,9 @@ namespace swift::gui::editors ui->cb_AircraftPartsLightsBeacon->setChecked(on); ui->cb_AircraftPartsLightsNav->setChecked(on); ui->cb_AircraftPartsLightsLogo->setChecked(on); + ui->cb_AircraftPartsLightsWing->setChecked(on); + ui->cb_AircraftPartsLightsRecognition->setChecked(on); + ui->cb_AircraftPartsLightsCabin->setChecked(on); } void CAircraftPartsForm::setAllEngines() @@ -115,10 +118,13 @@ namespace swift::gui::editors aviation::CAircraftParts CAircraftPartsForm::guiToAircraftParts() const { + // added new values for lights and engines here const CAircraftLights lights( ui->cb_AircraftPartsLightsStrobe->isChecked(), ui->cb_AircraftPartsLightsLanding->isChecked(), ui->cb_AircraftPartsLightsTaxi->isChecked(), ui->cb_AircraftPartsLightsBeacon->isChecked(), - ui->cb_AircraftPartsLightsNav->isChecked(), ui->cb_AircraftPartsLightsLogo->isChecked()); + ui->cb_AircraftPartsLightsNav->isChecked(), ui->cb_AircraftPartsLightsLogo->isChecked(), + ui->cb_AircraftPartsLightsRecognition->isChecked(), ui->cb_AircraftPartsLightsCabin->isChecked(), + ui->cb_AircraftPartsLightsWing->isChecked()); const CAircraftEngineList engines( { ui->cb_AircraftPartsEngine1->isChecked(), ui->cb_AircraftPartsEngine2->isChecked(), ui->cb_AircraftPartsEngine3->isChecked(), ui->cb_AircraftPartsEngine4->isChecked(), @@ -143,6 +149,7 @@ namespace swift::gui::editors ui->cb_AircraftPartsLightsNav->setChecked(lights.isNavOn()); ui->cb_AircraftPartsLightsStrobe->setChecked(lights.isStrobeOn()); ui->cb_AircraftPartsLightsTaxi->setChecked(lights.isTaxiOn()); + ui->cb_AircraftPartsLightsWing->setChecked(lights.isWingOn()); const CAircraftEngineList engines = parts.getEngines(); ui->cb_AircraftPartsEngine1->setChecked(engines.isEngineOn(1)); diff --git a/src/gui/editors/aircraftpartsform.ui b/src/gui/editors/aircraftpartsform.ui index ee86bbb118..9d28ebb74c 100644 --- a/src/gui/editors/aircraftpartsform.ui +++ b/src/gui/editors/aircraftpartsform.ui @@ -32,7 +32,7 @@ 3 - + Strobe @@ -70,7 +70,31 @@ - + + + + + Wing + + + + + + + Recognition + + + + + + + Cabin + + + + + + Nav @@ -91,7 +115,7 @@ - + Beacon @@ -140,7 +164,7 @@ - + Logo diff --git a/src/gui/models/aircraftmodellistmodel.cpp b/src/gui/models/aircraftmodellistmodel.cpp index ababff5a81..346f77a46b 100644 --- a/src/gui/models/aircraftmodellistmodel.cpp +++ b/src/gui/models/aircraftmodellistmodel.cpp @@ -36,7 +36,6 @@ namespace swift::gui::models (void)QT_TRANSLATE_NOOP("CAircraftModelListModel", "model"); } - // TODO TZ check if some columns can be hidden automatically for different sims void CAircraftModelListModel::setAircraftModelMode(CAircraftModelListModel::AircraftModelMode mode) { if (m_mode == mode) { return; } diff --git a/src/misc/CMakeLists.txt b/src/misc/CMakeLists.txt index 74c38efe94..709444022e 100644 --- a/src/misc/CMakeLists.txt +++ b/src/misc/CMakeLists.txt @@ -535,6 +535,8 @@ add_library(misc SHARED simulation/flightgear/flightgearutil.h simulation/msfs2024/aircraftmodelloadermsfs2024.cpp simulation/msfs2024/aircraftmodelloadermsfs2024.h + simulation/msfs2024/simconnectutilities.cpp + simulation/msfs2024/simconnectutilities.h simulation/fscommon/aircraftcfgentries.cpp simulation/fscommon/aircraftcfgentries.h simulation/fscommon/aircraftcfgentrieslist.cpp @@ -681,7 +683,7 @@ add_library(misc SHARED weather/windlayer.h weather/windlayerlist.cpp weather/windlayerlist.h -) + ) if(APPLE) target_sources(misc PRIVATE diff --git a/src/misc/aviation/aircraftlights.cpp b/src/misc/aviation/aircraftlights.cpp index cab9cd0a3b..2886009013 100644 --- a/src/misc/aviation/aircraftlights.cpp +++ b/src/misc/aviation/aircraftlights.cpp @@ -20,17 +20,23 @@ namespace swift::misc::aviation CAircraftLights::CAircraftLights(bool strobeOn, bool landingOn, bool taxiOn, bool beaconOn, bool navOn, bool logoOn, bool recognition, bool cabin) : m_strobeOn(strobeOn), m_landingOn(landingOn), m_taxiOn(taxiOn), m_beaconOn(beaconOn), m_navOn(navOn), - m_logoOn(logoOn), m_recognition(recognition), m_cabin(cabin) + m_logoOn(logoOn), m_recognitionOn(recognition), m_cabinOn(cabin) + {} + + CAircraftLights::CAircraftLights(bool strobeOn, bool landingOn, bool taxiOn, bool beaconOn, bool navOn, bool logoOn, + bool recognition, bool cabin, bool wing) + : m_strobeOn(strobeOn), m_landingOn(landingOn), m_taxiOn(taxiOn), m_beaconOn(beaconOn), m_navOn(navOn), + m_logoOn(logoOn), m_recognitionOn(recognition), m_cabinOn(cabin), m_wingOn(wing) {} CAircraftLights CAircraftLights::allLightsOn() { - return CAircraftLights { true, true, true, true, true, true, true, true }; + return CAircraftLights { true, true, true, true, true, true, true, true, true }; } CAircraftLights CAircraftLights::allLightsOff() { - return CAircraftLights { false, false, false, false, false, false, false, false }; + return CAircraftLights { false, false, false, false, false, false, false, false, false }; } QString CAircraftLights::convertToQString(bool i18n) const @@ -39,7 +45,8 @@ namespace swift::misc::aviation const QString s = u"strobe: " % boolToYesNo(m_strobeOn) % u" landing: " % boolToYesNo(m_landingOn) % u" taxi: " % boolToYesNo(m_taxiOn) % u" beacon: " % boolToYesNo(m_beaconOn) % u" nav: " % boolToYesNo(m_navOn) % u" logo: " % boolToYesNo(m_logoOn) % u" recognition: " % - boolToYesNo(m_recognition) % u" cabin: " % boolToYesNo(m_cabin); + boolToYesNo(m_recognitionOn) % u" cabin: " % boolToYesNo(m_cabinOn) % u" cabin: " % + boolToYesNo(m_wingOn); return s; } @@ -57,8 +64,9 @@ namespace swift::misc::aviation case IndexNav: return QVariant::fromValue(m_navOn); case IndexStrobe: return QVariant::fromValue(m_strobeOn); case IndexTaxi: return QVariant::fromValue(m_taxiOn); - case IndexRecognition: return QVariant::fromValue(m_recognition); - case IndexCabin: return QVariant::fromValue(m_cabin); + case IndexRecognition: return QVariant::fromValue(m_recognitionOn); + case IndexCabin: return QVariant::fromValue(m_cabinOn); + case IndexWing: return QVariant::fromValue(m_wingOn); default: return CValueObject::propertyByIndex(index); } } @@ -81,8 +89,9 @@ namespace swift::misc::aviation case IndexNav: m_navOn = variant.toBool(); break; case IndexStrobe: m_strobeOn = variant.toBool(); break; case IndexTaxi: m_taxiOn = variant.toBool(); break; - case IndexCabin: m_cabin = variant.toBool(); break; - case IndexRecognition: m_recognition = variant.toBool(); break; + case IndexCabin: m_cabinOn = variant.toBool(); break; + case IndexRecognition: m_recognitionOn = variant.toBool(); break; + case IndexWing: m_wingOn = variant.toBool(); break; default: CValueObject::setPropertyByIndex(index, variant); break; } } @@ -99,8 +108,9 @@ namespace swift::misc::aviation case IndexNav: return Compare::compare(m_navOn, compareValue.isNavOn()); case IndexStrobe: return Compare::compare(m_strobeOn, compareValue.isStrobeOn()); case IndexTaxi: return Compare::compare(m_taxiOn, compareValue.isTaxiOn()); - case IndexCabin: return Compare::compare(m_cabin, compareValue.isCabinOn()); - case IndexRecognition: return Compare::compare(m_recognition, compareValue.isRecognitionOn()); + case IndexCabin: return Compare::compare(m_cabinOn, compareValue.isCabinOn()); + case IndexRecognition: return Compare::compare(m_recognitionOn, compareValue.isRecognitionOn()); + case IndexWing: return Compare::compare(m_wingOn, compareValue.isWingOn()); default: break; } return 0; @@ -114,8 +124,9 @@ namespace swift::misc::aviation m_navOn = true; m_strobeOn = true; m_taxiOn = true; - m_cabin = true; - m_recognition = true; + m_cabinOn = true; + m_recognitionOn = true; + m_wingOn = true; } void CAircraftLights::setAllOff() @@ -126,7 +137,8 @@ namespace swift::misc::aviation m_navOn = false; m_strobeOn = false; m_taxiOn = false; - m_recognition = false; - m_cabin = false; + m_recognitionOn = false; + m_cabinOn = false; + m_wingOn = false; } } // namespace swift::misc::aviation diff --git a/src/misc/aviation/aircraftlights.h b/src/misc/aviation/aircraftlights.h index 846ce3df04..e1740fef5b 100644 --- a/src/misc/aviation/aircraftlights.h +++ b/src/misc/aviation/aircraftlights.h @@ -33,7 +33,8 @@ namespace swift::misc::aviation IndexNav, IndexLogo, IndexRecognition, - IndexCabin + IndexCabin, + IndexWing, }; //! Default constructor @@ -49,6 +50,10 @@ namespace swift::misc::aviation CAircraftLights(bool strobeOn, bool landingOn, bool taxiOn, bool beaconOn, bool navOn, bool logoOn, bool recognition, bool cabin); + //! Constructor + CAircraftLights(bool strobeOn, bool landingOn, bool taxiOn, bool beaconOn, bool navOn, bool logoOn, + bool recognitionOn, bool cabin, bool wingOn); + //! Strobes lights on? bool isStrobeOn() const { return m_strobeOn; } @@ -86,16 +91,22 @@ namespace swift::misc::aviation void setLogoOn(bool on) { m_logoOn = on; } //! Recognition lights on? - bool isRecognitionOn() const { return m_recognition; } + bool isRecognitionOn() const { return m_recognitionOn; } //! Set recognition lights - void setRecognitionOn(bool on) { m_recognition = on; } + void setRecognitionOn(bool on) { m_recognitionOn = on; } //! Cabin lights on? - bool isCabinOn() const { return m_cabin; } + bool isCabinOn() const { return m_cabinOn; } //! Set cabin lights - void setCabinOn(bool on) { m_cabin = on; } + void setCabinOn(bool on) { m_cabinOn = on; } + + //! Wing light on? + bool isWingOn() const { return m_wingOn; } + + //! Set wing lights + void setWingOn(bool on) { m_wingOn = on; } //! All on void setAllOn(); @@ -135,9 +146,11 @@ namespace swift::misc::aviation bool m_beaconOn = false; bool m_navOn = false; bool m_logoOn = false; - bool m_recognition = false; //!< not supported by aircraft config (VATSIM) - bool m_cabin = false; //!< not supported by aircraft config (VATSIM) + bool m_recognitionOn = false; //!< not supported by aircraft config (VATSIM) + bool m_cabinOn = false; //!< not supported by aircraft config (VATSIM) + bool m_wingOn = false; //!< not supported by aircraft config (VATSIM) + // TODO TZ check if disabled lights can be activated. for testing we keep them enabled in JSON SWIFT_METACLASS( CAircraftLights, SWIFT_METAMEMBER(isNull, 0, DisabledForJson), // disable since JSON is used for network @@ -147,8 +160,12 @@ namespace swift::misc::aviation SWIFT_METAMEMBER_NAMED(beaconOn, "beacon_on"), SWIFT_METAMEMBER_NAMED(navOn, "nav_on"), SWIFT_METAMEMBER_NAMED(logoOn, "logo_on"), - SWIFT_METAMEMBER(recognition, 0, DisabledForJson), // disable since JSON is used for network - SWIFT_METAMEMBER(cabin, 0, DisabledForJson) // disable since JSON is used for network + SWIFT_METAMEMBER_NAMED(recognitionOn,"recognition_on"), + SWIFT_METAMEMBER_NAMED(cabinOn, "cabin_on"), + SWIFT_METAMEMBER_NAMED(wingOn, "wing_on") + //SWIFT_METAMEMBER(recognitionOn, 0, DisabledForJson), // disable since JSON is used for network + //SWIFT_METAMEMBER(cabinOn, 0, DisabledForJson), // disable since JSON is used for network + //SWIFT_METAMEMBER(wingOn, 0, DisabledForJson) // disable since JSON is used for network ); }; } // namespace swift::misc::aviation diff --git a/src/misc/simulation/aircraftmodelloader.cpp b/src/misc/simulation/aircraftmodelloader.cpp index e25b9743e6..820475d48e 100644 --- a/src/misc/simulation/aircraftmodelloader.cpp +++ b/src/misc/simulation/aircraftmodelloader.cpp @@ -131,7 +131,7 @@ namespace swift::misc::simulation return; } - // TODO TZ + // TODO TZ 2024: skip loading for MSFS2024? QStringList modelDirs = { "", "" }; // if (simulator.isMSFS2024()) //{ diff --git a/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp b/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp index 07ee7fc602..2e9035d884 100644 --- a/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp +++ b/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp @@ -58,7 +58,7 @@ namespace swift::misc::simulation::msfs2024 // TODO TZ Implement model queries via SimConnect if possible // misc shut not include simconnect headers or plugins directly - + // still no idea how to do that const CSimulatorInfo simulatorInfo = CSimulatorInfo::msfs2024(); allModels = CCentralMultiSimulatorModelCachesProvider::modelCachesInstance().getSynchronizedCachedModels(simulatorInfo); @@ -83,7 +83,7 @@ namespace swift::misc::simulation::msfs2024 if (m_parserWorker && !m_parserWorker->isFinished()) { return; } emit this->diskLoadingStarted(simulator, mode); - // TODO TZ simplify, we don't need directories + // TODO TZ need help: simplify, we don't need directories in this->performParsing for MSFS2024 m_parserWorker = CWorker::fromTask(this, "CAircraftModelLoaderMsfs2024::performParsing", [this, modelDirs, excludedDirectoryPatterns, modelConsolidation]() { auto models = this->performParsing(); diff --git a/src/misc/simulation/msfs2024/simconnectutilities.cpp b/src/misc/simulation/msfs2024/simconnectutilities.cpp new file mode 100644 index 0000000000..c4cc398c37 --- /dev/null +++ b/src/misc/simulation/msfs2024/simconnectutilities.cpp @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +#include "misc/simulation/msfs2024/simconnectutilities.h" + +#include +#include +#include +#include + +#include "misc/stringutils.h" + +using namespace swift::misc; +using namespace swift::misc::aviation; + +namespace swift::misc::simulation::msfs2024 +{ + CSimConnectUtilities::CSimConnectUtilities() {} + + QString CSimConnectUtilities::resolveEnumToString(const DWORD id, const char *enumName) + { + const int i = CSimConnectUtilities::staticMetaObject.indexOfEnumerator(enumName); + if (i < 0) { return QStringLiteral("No enumerator for %1").arg(enumName); } + const QMetaEnum m = CSimConnectUtilities::staticMetaObject.enumerator(i); + const char *k = m.valueToKey(static_cast(id)); + return (k) ? QLatin1String(k) : QStringLiteral("Id '%1' not found for %2").arg(id).arg(enumName); + } + + QString CSimConnectUtilities::simConnectExceptionToString(const DWORD id) + { + return CSimConnectUtilities::resolveEnumToString(id, "SIMCONNECT_EXCEPTION"); + } + + QString CSimConnectUtilities::simConnectSurfaceTypeToString(const DWORD type, bool beautify) + { + QString sf = CSimConnectUtilities::resolveEnumToString(type, "SIMCONNECT_SURFACE"); + return beautify ? sf.replace('_', ' ') : sf; + } + + QString CSimConnectUtilities::simConnectReceiveIdToString(DWORD type) + { + const QString ri = CSimConnectUtilities::resolveEnumToString(type, "SIMCONNECT_RECV_ID"); + return ri; + } + + int CSimConnectUtilities::lightsToLightStates(const CAircraftLights &lights) + { + int lightMask = 0; + if (lights.isBeaconOn()) { lightMask |= Beacon; } + if (lights.isLandingOn()) { lightMask |= Landing; } + if (lights.isLogoOn()) { lightMask |= Logo; } + if (lights.isNavOn()) { lightMask |= Nav; } + if (lights.isStrobeOn()) { lightMask |= Strobe; } + if (lights.isTaxiOn()) { lightMask |= Taxi; } + return lightMask; + } + + void CSimConnectUtilities::registerMetadata() + { + qRegisterMetaType(); + qRegisterMetaType(); + } + + CWinDllUtils::DLLInfo CSimConnectUtilities::simConnectDllInfo() + { + const QList modules = CWinDllUtils::getModules(-1, "simconnect"); + if (modules.isEmpty()) + { + CWinDllUtils::DLLInfo info; + info.errorMsg = "No SimConnect.dll loaded"; + return info; + } + return CWinDllUtils::getDllInfo(modules.first().executable); + } +} // namespace swift::misc::simulation::msfs2024 diff --git a/src/misc/simulation/msfs2024/simconnectutilities.h b/src/misc/simulation/msfs2024/simconnectutilities.h new file mode 100644 index 0000000000..f2c2cbb95e --- /dev/null +++ b/src/misc/simulation/msfs2024/simconnectutilities.h @@ -0,0 +1,204 @@ +// 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_MISC_SIMULATION_MSFS2024_SIMCONNECTUTILITIES_H +#define SWIFT_MISC_SIMULATION_MSFS2024_SIMCONNECTUTILITIES_H + +#include +#include +#include +#include + +#include "misc/aviation/aircraftlights.h" +#include "misc/simulation/simulatorinfo.h" +#include "misc/swiftmiscexport.h" +#include "misc/windllutils.h" + +// Apart from the below definitions, the following code is OS independent, +// though it does not make sense to be used on non WIN machines. +// But it allows such parts to compile on all platforms. +#ifdef Q_OS_WIN +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include +#else +using DWORD = unsigned long; //!< Fake Windows DWORD +#endif + +namespace swift::misc::simulation::msfs2024 +{ + //! Utilities for SimConnect + //! \remark not using the simconnect.h headers as Misc classes are not driver aware + class SWIFT_MISC_EXPORT CSimConnectUtilities : public QObject + { + Q_OBJECT + + public: + //! Resolve SimConnect exception (based on Qt metadata). + //! \param id enum element + //! \return enum element's name + static QString simConnectExceptionToString(const DWORD id); + + //! Resolve SimConnect surface (based on Qt metadata). + //! \param type enum element + //! \param beautify remove "_" + static QString simConnectSurfaceTypeToString(const DWORD type, bool beautify = true); + + //! SimConnect surfaces. + //! \sa http://msdn.microsoft.com/en-us/library/cc526981.aspx#AircraftFlightInstrumentationData + enum SIMCONNECT_SURFACE + { + Concrete, + Grass, + Water, + Grass_bumpy, + Asphalt, + Short_grass, + Long_grass, + Hard_turf, + Snow, + Ice, + Urban, + Forest, + Dirt, + Coral, + Gravel, + Oil_treated, + Steel_mats, + Bituminus, + Brick, + Macadam, + Planks, + Sand, + Shale, + Tarmac, + Wright_flyer_track + }; + Q_ENUM(SIMCONNECT_SURFACE) + + //! SimConnect exceptions. + enum SIMCONNECT_EXCEPTION + { + SIMCONNECT_EXCEPTION_NONE, + SIMCONNECT_EXCEPTION_ERROR, + SIMCONNECT_EXCEPTION_SIZE_MISMATCH, + SIMCONNECT_EXCEPTION_UNRECOGNIZED_ID, + SIMCONNECT_EXCEPTION_UNOPENED, + SIMCONNECT_EXCEPTION_VERSION_MISMATCH, + SIMCONNECT_EXCEPTION_TOO_MANY_GROUPS, + SIMCONNECT_EXCEPTION_NAME_UNRECOGNIZED, + SIMCONNECT_EXCEPTION_TOO_MANY_EVENT_NAMES, + SIMCONNECT_EXCEPTION_EVENT_ID_DUPLICATE, + SIMCONNECT_EXCEPTION_TOO_MANY_MAPS, + SIMCONNECT_EXCEPTION_TOO_MANY_OBJECTS, + SIMCONNECT_EXCEPTION_TOO_MANY_REQUESTS, + SIMCONNECT_EXCEPTION_WEATHER_INVALID_PORT, + SIMCONNECT_EXCEPTION_WEATHER_INVALID_METAR, + SIMCONNECT_EXCEPTION_WEATHER_UNABLE_TO_GET_OBSERVATION, + SIMCONNECT_EXCEPTION_WEATHER_UNABLE_TO_CREATE_STATION, + SIMCONNECT_EXCEPTION_WEATHER_UNABLE_TO_REMOVE_STATION, + SIMCONNECT_EXCEPTION_INVALID_DATA_TYPE, + SIMCONNECT_EXCEPTION_INVALID_DATA_SIZE, + SIMCONNECT_EXCEPTION_DATA_ERROR, + SIMCONNECT_EXCEPTION_INVALID_ARRAY, + SIMCONNECT_EXCEPTION_CREATE_OBJECT_FAILED, + SIMCONNECT_EXCEPTION_LOAD_FLIGHTPLAN_FAILED, + SIMCONNECT_EXCEPTION_OPERATION_INVALID_FOR_OBJECT_TYPE, + SIMCONNECT_EXCEPTION_ILLEGAL_OPERATION, + SIMCONNECT_EXCEPTION_ALREADY_SUBSCRIBED, + SIMCONNECT_EXCEPTION_INVALID_ENUM, + SIMCONNECT_EXCEPTION_DEFINITION_ERROR, + SIMCONNECT_EXCEPTION_DUPLICATE_ID, + SIMCONNECT_EXCEPTION_DATUM_ID, + SIMCONNECT_EXCEPTION_OUT_OF_BOUNDS, + SIMCONNECT_EXCEPTION_ALREADY_CREATED, + SIMCONNECT_EXCEPTION_OBJECT_OUTSIDE_REALITY_BUBBLE, + SIMCONNECT_EXCEPTION_OBJECT_CONTAINER, + SIMCONNECT_EXCEPTION_OBJECT_AI, + SIMCONNECT_EXCEPTION_OBJECT_ATC, + SIMCONNECT_EXCEPTION_OBJECT_SCHEDULE + }; + Q_ENUM(SIMCONNECT_EXCEPTION) + + //! Lights for FSX/P3D "LIGHT ON STATES" + //! \sa http://www.prepar3d.com/SDKv2/LearningCenter/utilities/variables/simulation_variables.html + enum LIGHT_STATES + { + Nav = 0x0001, + Beacon = 0x0002, + Landing = 0x0004, + Taxi = 0x0008, + Strobe = 0x0010, + Panel = 0x0020, + Recognition = 0x0040, + Wing = 0x0080, + Logo = 0x0100, + Cabin = 0x0200 + }; + + //! Receive IDs for SimConnect + enum SIMCONNECT_RECV_ID + { + SIMCONNECT_RECV_ID_NULL, + SIMCONNECT_RECV_ID_EXCEPTION, + SIMCONNECT_RECV_ID_OPEN, + SIMCONNECT_RECV_ID_QUIT, + SIMCONNECT_RECV_ID_EVENT, + SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE, + SIMCONNECT_RECV_ID_EVENT_FILENAME, + SIMCONNECT_RECV_ID_EVENT_FRAME, + SIMCONNECT_RECV_ID_SIMOBJECT_DATA, + SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE, + SIMCONNECT_RECV_ID_WEATHER_OBSERVATION, + SIMCONNECT_RECV_ID_CLOUD_STATE, + SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID, + SIMCONNECT_RECV_ID_RESERVED_KEY, + SIMCONNECT_RECV_ID_CUSTOM_ACTION, + SIMCONNECT_RECV_ID_SYSTEM_STATE, + SIMCONNECT_RECV_ID_CLIENT_DATA, + SIMCONNECT_RECV_ID_EVENT_WEATHER_MODE, + SIMCONNECT_RECV_ID_AIRPORT_LIST, + SIMCONNECT_RECV_ID_VOR_LIST, + SIMCONNECT_RECV_ID_NDB_LIST, + SIMCONNECT_RECV_ID_WAYPOINT_LIST, + SIMCONNECT_RECV_ID_EVENT_MULTIPLAYER_SERVER_STARTED, + SIMCONNECT_RECV_ID_EVENT_MULTIPLAYER_CLIENT_STARTED, + SIMCONNECT_RECV_ID_EVENT_MULTIPLAYER_SESSION_ENDED, + SIMCONNECT_RECV_ID_EVENT_RACE_END, + SIMCONNECT_RECV_ID_EVENT_RACE_LAP, + }; + Q_ENUM(SIMCONNECT_RECV_ID) + + //! Receive id to string + static QString simConnectReceiveIdToString(DWORD type); + + //! Lights to states + static int lightsToLightStates(const aviation::CAircraftLights &lights); + + //! Get info about SimConnect DLL + static swift::misc::CWinDllUtils::DLLInfo simConnectDllInfo(); + + //! Register metadata + static void registerMetadata(); + + private: + //! + //! Resolve enum value to its cleartext (based on Qt metadata). + //! \param id enum element + //! \param enumName name of the resolved enum + //! \return enum element's name + static QString resolveEnumToString(const DWORD id, const char *enumName); + + //! Hidden constructor + CSimConnectUtilities(); + }; +} // namespace swift::misc::simulation::msfs2024 + +Q_DECLARE_METATYPE(swift::misc::simulation::msfs2024::CSimConnectUtilities::SIMCONNECT_EXCEPTION) +Q_DECLARE_METATYPE(swift::misc::simulation::msfs2024::CSimConnectUtilities::SIMCONNECT_SURFACE) +Q_DECLARE_METATYPE(swift::misc::simulation::msfs2024::CSimConnectUtilities::SIMCONNECT_RECV_ID) + +#endif // SWIFT_MISC_SIMULATION_MSFS2024_SIMCONNECTUTILITIES_H diff --git a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp index 933e5c00f1..bb0841c799 100644 --- a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp +++ b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp @@ -130,6 +130,13 @@ namespace swift::simplugin::msfs2024common hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT NAV", "Bool"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT LOGO", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT RECOGNITION", + "Bool"); + hr += + SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT CABIN", "Bool"); + hr += + SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "LIGHT WING", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "TRANSPONDER CODE:1", nullptr); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, @@ -171,6 +178,11 @@ namespace swift::simplugin::msfs2024common "GENERAL ENG COMBUSTION:3", "Bool"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "GENERAL ENG COMBUSTION:4", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "GENERAL ENG COMBUSTION:5", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, + "GENERAL ENG COMBUSTION:6", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "VELOCITY WORLD X", "Feet per second"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "VELOCITY WORLD Y", @@ -236,6 +248,10 @@ namespace swift::simplugin::msfs2024common "GENERAL ENG COMBUSTION:3", "Bool"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, "GENERAL ENG COMBUSTION:4", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "GENERAL ENG COMBUSTION:5", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights, + "GENERAL ENG COMBUSTION:6", "Bool"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraftTitle, "TITLE", nullptr, SIMCONNECT_DATATYPE_STRING256); @@ -255,12 +271,12 @@ namespace swift::simplugin::msfs2024common "Bool"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, "LIGHT LOGO", "Bool"); - hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, "LIGHT NAV", - "Bool"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, "LIGHT RECOGNITION", "Bool"); hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, "LIGHT CABIN", "Bool"); + hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights, + "LIGHT WING", "Bool"); if (isFailure(hr)) { @@ -473,11 +489,12 @@ namespace swift::simplugin::msfs2024common { return std::tie(flapsLeadingEdgeLeftPercent, flapsLeadingEdgeRightPercent, flapsTrailingEdgeLeftPercent, flapsTrailingEdgeRightPercent, gearHandlePosition, spoilersHandlePosition, engine1Combustion, - engine2Combustion, engine3Combustion, engine4Combustion) == + engine2Combustion, engine3Combustion, engine4Combustion, engine5Combustion, + engine6Combustion) == std::tie(rhs.flapsLeadingEdgeLeftPercent, rhs.flapsLeadingEdgeRightPercent, rhs.flapsTrailingEdgeLeftPercent, rhs.flapsTrailingEdgeRightPercent, rhs.gearHandlePosition, rhs.spoilersHandlePosition, rhs.engine1Combustion, rhs.engine2Combustion, rhs.engine3Combustion, - rhs.engine4Combustion); + rhs.engine4Combustion, rhs.engine5Combustion, rhs.engine6Combustion); } void DataDefinitionRemoteAircraftPartsWithoutLights::setAllEngines(bool on) @@ -486,6 +503,8 @@ namespace swift::simplugin::msfs2024common engine2Combustion = on ? 1 : 0; engine3Combustion = on ? 1 : 0; engine4Combustion = on ? 1 : 0; + engine5Combustion = on ? 1 : 0; + engine6Combustion = on ? 1 : 0; } void DataDefinitionRemoteAircraftPartsWithoutLights::setEngine(int number1based, bool on) @@ -497,6 +516,8 @@ namespace swift::simplugin::msfs2024common case 2: engine2Combustion = v; break; case 3: engine3Combustion = v; break; case 4: engine4Combustion = v; break; + case 5: engine5Combustion = v; break; + case 6: engine6Combustion = v; break; default: break; } } @@ -523,6 +544,8 @@ namespace swift::simplugin::msfs2024common engine2Combustion = -1; engine3Combustion = -1; engine4Combustion = -1; + engine5Combustion = -1; + engine6Combustion = -1; } void DataDefinitionRemoteAircraftPartsWithoutLights::initFromParts(const CAircraftParts &parts) @@ -544,7 +567,7 @@ namespace swift::simplugin::msfs2024common CAircraftLights DataDefinitionRemoteAircraftLights::toLights() const { return CAircraftLights(dtb(lightStrobe), dtb(lightLanding), dtb(lightTaxi), dtb(lightBeacon), dtb(lightNav), - dtb(lightLogo), dtb(lightRecognition), dtb(lightCabin)); + dtb(lightLogo), dtb(lightRecognition), dtb(lightCabin), dtb(lightWing)); } QString DataDefinitionClientAreaSb::toQString() const diff --git a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h index 2503ea69a1..c1d1e730e7 100644 --- a/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h +++ b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h @@ -47,7 +47,10 @@ namespace swift::simplugin::msfs2024common double lightBeacon; //!< Is beacon light on? double lightNav; //!< Is nav light on? double lightLogo; //!< Is logo light on? - // 18 + double lightRecognition; + double lightCabin; //!< Is cabin light on? + double lightWing; //!< Is wing light on? + // 21 double transponderCode; //!< Transponder Code double com1ActiveMHz; //!< COM1 active frequency double com2ActiveMHz; //!< COM2 active frequency @@ -60,26 +63,28 @@ namespace swift::simplugin::msfs2024common double comTest2; //!< COM2 test double comStatus1; //!< COM1 status double comStatus2; //!< COM2 status - // 30 + // 33 double flapsHandlePosition; //!< Flaps handle position in percent double spoilersHandlePosition; //!< Spoilers out? (flag) double gearHandlePosition; //!< Gear handle position (flag) - // 33 + // 36 double numberOfEngines; //!< Number of engines double engine1Combustion; //!< Engine 1 combustion flag double engine2Combustion; //!< Engine 2 combustion flag double engine3Combustion; //!< Engine 3 combustion flag double engine4Combustion; //!< Engine 4 combustion flag - // 38 + double engine5Combustion; //!< Engine 5 combustion flag + double engine6Combustion; //!< Engine 6 combustion flag + // 43 double velocityWorldX; //!< Velocity World X double velocityWorldY; //!< Velocity World Y double velocityWorldZ; //!< Velocity World Z double rotationVelocityBodyX; //!< Rotation Velocity Body X double rotationVelocityBodyY; //!< Rotation Velocity Body Y double rotationVelocityBodyZ; //!< Rotation Velocity Body Z - // 44 + // 49 double altitudeCalibratedFt; //!< Altitude without temperature effect (ft, FS2020) - // 45 + // 50 }; //! Data struct of aircraft position @@ -159,6 +164,8 @@ namespace swift::simplugin::msfs2024common double engine2Combustion; //!< Engine 2 combustion flag double engine3Combustion; //!< Engine 3 combustion flag double engine4Combustion; //!< Engine 4 combustion flag + double engine5Combustion; //!< Engine 5 combustion flag + double engine6Combustion; //!< Engine 6 combustion flag //! Ctor DataDefinitionRemoteAircraftPartsWithoutLights(); @@ -199,7 +206,7 @@ namespace swift::simplugin::msfs2024common double lightLogo; //!< Is logo light on? double lightRecognition; //!< Is recognition light on double lightCabin; //!< Is cabin light on - + double lightWing; //!< Is cabin light on //! Convert to lights swift::misc::aviation::CAircraftLights toLights() const; }; diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024.cpp index f0e0477d77..10ff7061c5 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024.cpp @@ -22,7 +22,7 @@ namespace swift::simplugin::msfs2024 IClientProvider *clientProvider, QObject *parent) : CSimulatorMsfs2024(info, ownAircraftProvider, remoteAircraftProvider, clientProvider, parent) { - this->setDefaultModel({ "A320neo V2", CAircraftModel::TypeModelMatchingDefaultModel, + this->setDefaultModel({ "A320NEO V2", CAircraftModel::TypeModelMatchingDefaultModel, "Airbus A320 default model", CAircraftIcaoCode("A320", "L2J") }); } diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp index 2a76dbc2ef..6385e5376c 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp @@ -37,8 +37,8 @@ #include "misc/simulation/fscommon/aircraftcfgparser.h" #include "misc/simulation/fscommon/bcdconversions.h" #include "misc/simulation/fscommon/fscommonutil.h" -#include "misc/simulation/fsx/simconnectutilities.h" #include "misc/simulation/interpolation/interpolatormulti.h" +#include "misc/simulation/msfs2024/simconnectutilities.h" #include "misc/simulation/settings/simulatorsettings.h" #include "misc/simulation/simulatorplugininfo.h" #include "misc/statusmessagelist.h" @@ -56,8 +56,7 @@ using namespace swift::misc::math; using namespace swift::misc::simulation; using namespace swift::misc::simulation::data; using namespace swift::misc::simulation::fscommon; -using namespace swift::misc::simulation::fsx; -// using namespace swift::misc::simulation::msfs2024; +using namespace swift::misc::simulation::msfs2024; using namespace swift::misc::simulation::settings; using namespace swift::core; using namespace swift::core::db; @@ -362,7 +361,6 @@ namespace swift::simplugin::msfs2024common sSimmobjectLoadedState.bLoadStarted = true; CLogMessage(this).info(u"Start loading SimObjects and liverys from simulator"); - // TODO TZ a message should be displayed here because the gui freezes during loading large amounts of data const CStatusMessage m = CStatusMessage(this, CStatusMessage::SeverityInfo, u"Start loading SimObjects and liverys from simulator"); } @@ -399,9 +397,6 @@ namespace swift::simplugin::msfs2024common void CSimulatorMsfs2024::setSimObjectAndLiveries() { - // TODO TZ a message should be displayed here because the gui freezes during loading - // better: move to the background (e.g., use CWorker::fromTask(...)), avoid GUI freeze. - CLogMessage(this).info(u"%1 SimObjects and Liveries in vSimObjectsAndLiveries") << vSimObjectsAndLiveries.size(); @@ -410,7 +405,7 @@ namespace swift::simplugin::msfs2024common return QVariant(); // void-Result }); - // TODO TZ where to place this message better? + // TODO TZ need help: Where can a message be placed indicating that loading is complete? worker->then(this, [=] { CLogMessage(this).info(u"SimObjects and Liveries in vSimObjectsAndLiveries ready"); }); } @@ -567,7 +562,7 @@ namespace swift::simplugin::msfs2024common CLogMessage(this).info(u"%1 SimObjects and Liveries in DbModelList") << NewSet.size(); - // TODO TZ only for debugging + // TODO TZ can used only for debugging // int cstoremodels = writeSimObjectsAndLiveriesToFile(NewSet); } } @@ -676,17 +671,18 @@ namespace swift::simplugin::msfs2024common this->sendRemoteAircraftPartsToSimulator(simObject, parts); u++; } - if (!situation.isNull()) - { - SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToFsxPosition(situation, true); - const bool traceSendId = this->isTracingSendId(); - const HRESULT hr = this->logAndTraceSendId( - SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetPosition, - static_cast(simObject.getObjectId()), 0, 0, - sizeof(SIMCONNECT_DATA_INITPOSITION), &position), - traceSendId, simObject, "Failed to set position", Q_FUNC_INFO, "SimConnect_SetDataOnSimObject"); - if (hr == S_OK) { u++; } - } + // TODO TZ check: The function call destroys the configured simulation. + // if (!situation.isNull()) + //{ + // SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToPosition(situation, true); + // const bool traceSendId = this->isTracingSendId(); + // const HRESULT hr = this->logAndTraceSendId( + // SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetPosition, + // static_cast(simObject.getObjectId()), 0, 0, + // sizeof(SIMCONNECT_DATA_INITPOSITION), &position), + // traceSendId, simObject, "Failed to set position", Q_FUNC_INFO, "SimConnect_SetDataOnSimObject"); + // if (hr == S_OK) { u++; } + //} return u > 0; } @@ -860,12 +856,14 @@ namespace swift::simplugin::msfs2024common return m_simConnectObjects.removeByOtherSimObject(trace.simObject); } + // TODO TZ check if nessesary in MSFS2024 void CSimulatorMsfs2024::removeCamera(CSimConnectObject &simObject) { // not in FSX Q_UNUSED(simObject) } + // TODO TZ check if nessesary in MSFS2024 void CSimulatorMsfs2024::removeObserver(CSimConnectObject &simObject) { // not in FSX @@ -883,7 +881,7 @@ namespace swift::simplugin::msfs2024common static const QString format("hh:mm:ss.zzz"); const QString untilString = QDateTime::fromMSecsSinceEpoch(traceUntil).toString(format); - CLogMessage(this).info(u"Triggered FSX/P3D auto trace until %1") << untilString; + CLogMessage(this).info(u"Triggered MSFS2024 auto trace until %1") << untilString; const QPointer myself(this); QTimer::singleShot(traceTimeMs * 1.2, this, [=] { // triggered by mself (ts check), otherwise ignore @@ -914,13 +912,13 @@ namespace swift::simplugin::msfs2024common if (simulatorOwnAircraft.pitchDeg < -90.0 || simulatorOwnAircraft.pitchDeg >= 90.0) { - CLogMessage(this).warning(u"FSX: Pitch value (own aircraft) out of limits: %1") + CLogMessage(this).warning(u"MSFS2024: Pitch value (own aircraft) out of limits: %1") << simulatorOwnAircraft.pitchDeg; } CAircraftSituation aircraftSituation; aircraftSituation.setMSecsSinceEpoch(ts); aircraftSituation.setPosition(position); - // MSFS has inverted pitch and bank angles + // MSFS2024 has inverted pitch and bank angles aircraftSituation.setPitch(CAngle(-simulatorOwnAircraft.pitchDeg, CAngleUnit::deg())); aircraftSituation.setBank(CAngle(-simulatorOwnAircraft.bankDeg, CAngleUnit::deg())); aircraftSituation.setHeading(CHeading(simulatorOwnAircraft.trueHeadingDeg, CHeading::True, CAngleUnit::deg())); @@ -946,13 +944,18 @@ namespace swift::simplugin::msfs2024common const CAircraftLights lights(dtb(simulatorOwnAircraft.lightStrobe), dtb(simulatorOwnAircraft.lightLanding), dtb(simulatorOwnAircraft.lightTaxi), dtb(simulatorOwnAircraft.lightBeacon), - dtb(simulatorOwnAircraft.lightNav), dtb(simulatorOwnAircraft.lightLogo)); + dtb(simulatorOwnAircraft.lightNav), dtb(simulatorOwnAircraft.lightLogo), + dtb(simulatorOwnAircraft.lightRecognition), dtb(simulatorOwnAircraft.lightCabin), + dtb(simulatorOwnAircraft.lightWing) + + ); CAircraftEngineList engines; - const QList helperList { dtb(simulatorOwnAircraft.engine1Combustion), - dtb(simulatorOwnAircraft.engine2Combustion), - dtb(simulatorOwnAircraft.engine3Combustion), - dtb(simulatorOwnAircraft.engine4Combustion) }; + const QList helperList { + dtb(simulatorOwnAircraft.engine1Combustion), dtb(simulatorOwnAircraft.engine2Combustion), + dtb(simulatorOwnAircraft.engine3Combustion), dtb(simulatorOwnAircraft.engine4Combustion), + dtb(simulatorOwnAircraft.engine5Combustion), dtb(simulatorOwnAircraft.engine6Combustion) + }; for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index) { @@ -1057,7 +1060,7 @@ namespace swift::simplugin::msfs2024common } else { --m_skipCockpitUpdateCycles; } - // TODO TZ check if we need to update terrain probes + // TODO TZ check this entire function for msfs2024 // slower updates if (m_ownAircraftUpdateCycles % 10 == 0) { @@ -1165,7 +1168,6 @@ namespace swift::simplugin::msfs2024common CSimConnectObject &so = m_simConnectObjects[cs]; if (so.isPendingRemoved()) { return; } - // TODO TZ verify model and livery QString combinedModelstring = QString::fromUtf8(remoteAircraftModel.title) + " " + QString::fromUtf8(remoteAircraftModel.livery); const QString modelString(combinedModelstring.trimmed()); @@ -1943,7 +1945,7 @@ namespace swift::simplugin::msfs2024common // TODO TZ handle underflow properly CStatusMessage underflowStatus; const SIMCONNECT_DATA_INITPOSITION initialPosition = - CSimulatorMsfs2024::aircraftSituationToFsxPosition(initialSituation, sendGround, true, &underflowStatus); + CSimulatorMsfs2024::aircraftSituationToPosition(initialSituation, sendGround, true, &underflowStatus); QString modelString(newRemoteAircraft.getShortModelString()); const QString modelLiveryString(newRemoteAircraft.getLiveryString()); @@ -1968,12 +1970,12 @@ namespace swift::simplugin::msfs2024common correspondingSimObject.getType() == CSimConnectObject::AircraftNonAtc) { CStatusMessage(this).warning( - u"Model '%1' for '%2' failed %1 time(s) before, using AICreateSimulatedObject now") - << newRemoteAircraft.getModelString() << callsign.toQString(); + u"Model '%1' for '%2' failed %3 time(s) before, using SimConnect_AICreateSimulatedObject_EX1 now") + << newRemoteAircraft.getModelString() << callsign.toQString() + << correspondingSimObject.getAddingExceptions(); - hr = SimConnect_AICreateNonATCAircraft_EX1(m_hSimConnect, modelStringBa.constData(), - modelLiveryBa.constData(), csBa.constData(), initialPosition, - requestId); + hr = SimConnect_AICreateSimulatedObject_EX1(m_hSimConnect, modelStringBa.constData(), + modelLiveryBa.constData(), initialPosition, requestId); type = CSimConnectObject::AircraftSimulatedObject; } @@ -2121,7 +2123,7 @@ namespace swift::simplugin::msfs2024common hr += SimConnect_SubscribeToSystemEvent(m_hSimConnect, SystemEventFlightLoaded, "FlightLoaded"); if (isFailure(hr)) { - CLogMessage(this).error(u"FSX plugin error: %1") << "SimConnect_SubscribeToSystemEvent failed"; + CLogMessage(this).error(u"MSFS2024 plugin error: %1") << "SimConnect_SubscribeToSystemEvent failed"; return hr; } @@ -2147,31 +2149,34 @@ namespace swift::simplugin::msfs2024common hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetTimeZuluHours, "ZULU_HOURS_SET"); hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetTimeZuluMinutes, "ZULU_MINUTES_SET"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandingLightsOff, "LANDING_LIGHTS_OFF"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandinglightsOn, "LANDING_LIGHTS_ON"); + // hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandingLightsOff, "LANDING_LIGHTS_OFF"); + // hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandinglightsOn, "LANDING_LIGHTS_ON"); hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandingLightsSet, "LANDING_LIGHTS_SET"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandingLightsToggle, "LANDING_LIGHTS_TOGGLE"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventPanelLightsOff, "PANEL_LIGHTS_OFF"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventPanelLightsOn, "PANEL_LIGHTS_ON"); + // hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLandingLightsToggle, "LANDING_LIGHTS_TOGGLE"); + + // hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventPanelLightsOff, "PANEL_LIGHTS_OFF"); + // hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventPanelLightsOn, "PANEL_LIGHTS_ON"); hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventPanelLightsSet, "PANEL_LIGHTS_SET"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesOff, "STROBES_OFF"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesOn, "STROBES_ON"); + + // hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesOff, "STROBES_OFF"); + // hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesOn, "STROBES_ON"); hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesSet, "STROBES_SET"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesToggle, "STROBES_TOGGLE"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleBeaconLights, "TOGGLE_BEACON_LIGHTS"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleCabinLights, "TOGGLE_CABIN_LIGHTS"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleLogoLights, "TOGGLE_LOGO_LIGHTS"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleNavLights, "TOGGLE_NAV_LIGHTS"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleRecognitionLights, - "TOGGLE_RECOGNITION_LIGHTS"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleTaxiLights, "TOGGLE_TAXI_LIGHTS"); - hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleWingLights, "TOGGLE_WING_LIGHTS"); + // hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventStrobesToggle, "STROBES_TOGGLE"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventBeaconLightsSet, "BEACON_LIGHTS_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventCabinLightsSet, "CABIN_LIGHTS_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventLogoLightsSet, "LOGO_LIGHTS_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventNavLightsSet, "NAV_LIGHTS_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventRecognitionLightsSet, "RECOGNITION_LIGHTS_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventTaxiLightsSet, "TAXI_LIGHTS_SET"); + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventWingLightsSet, "WING_LIGHTS_SET"); + + hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventGearSet, "GEAR_SET"); hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventFlapsSet, "FLAPS_SET"); if (isFailure(hr)) { - CLogMessage(this).error(u"FSX plugin error: %1") << "SimConnect_MapClientEventToSimEvent failed"; + CLogMessage(this).error(u"MSFS2024 plugin error: %1") << "SimConnect_MapClientEventToSimEvent failed"; return hr; } @@ -2201,7 +2206,7 @@ namespace swift::simplugin::msfs2024common HRESULT hr = this->initEvents(); if (isFailure(hr)) { - CLogMessage(this).error(u"FSX plugin: initEvents failed"); + CLogMessage(this).error(u"MSFS2024 plugin: initEvents failed"); return hr; } @@ -2209,7 +2214,7 @@ namespace swift::simplugin::msfs2024common hr += this->initDataDefinitionsWhenConnected(); if (isFailure(hr)) { - CLogMessage(this).error(u"FSX plugin: initDataDefinitionsWhenConnected failed"); + CLogMessage(this).error(u"MSFS2024 plugin: initDataDefinitionsWhenConnected failed"); return hr; } @@ -2218,7 +2223,7 @@ namespace swift::simplugin::msfs2024common void CSimulatorMsfs2024::updateRemoteAircraft() { - static_assert(sizeof(DataDefinitionRemoteAircraftPartsWithoutLights) == sizeof(double) * 10, + static_assert(sizeof(DataDefinitionRemoteAircraftPartsWithoutLights) == sizeof(double) * 12, "DataDefinitionRemoteAircraftPartsWithoutLights has an incorrect size."); Q_ASSERT_X(CThreadUtils::isInThisThread(this), Q_FUNC_INFO, "thread"); @@ -2283,7 +2288,7 @@ namespace swift::simplugin::msfs2024common situation.setAltitude({ situation.getAltitude() + m_altitudeDelta * altitudeDeltaWeight, situation.getAltitude().getReferenceDatum() }); - SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToFsxPosition(situation, sendGround); + SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToPosition(situation, sendGround); const HRESULT hr = this->logAndTraceSendId( SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetPosition, @@ -2371,28 +2376,81 @@ namespace swift::simplugin::msfs2024common SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), traceId, simObject, "Failed so set flaps", Q_FUNC_INFO, "SimConnect_TransmitClientEvent::EventFlapsSet"); - // lights we can set directly const HRESULT hr3 = this->logAndTraceSendId( + SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventGearSet, parts.isFixedGearDown() ? 1.0 : 0.0, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed so set gears", Q_FUNC_INFO, "SimConnect_TransmitClientEvent::EventGearSet"); + + const CAircraftLights lightsIsState = simObject.getCurrentLightsInSimulator(); + if (lights == lightsIsState) { return isOk(hr1, hr2, hr3); } + + // lights we can set directly + const HRESULT hr4 = this->logAndTraceSendId( SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventLandingLightsSet, lights.isLandingOn() ? 1.0 : 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), traceId, simObject, "Failed so set landing lights", Q_FUNC_INFO, "SimConnect_TransmitClientEvent::EventLandingLightsSet"); - const HRESULT hr4 = + const HRESULT hr5 = this->logAndTraceSendId(SimConnect_TransmitClientEvent( m_hSimConnect, objectId, EventStrobesSet, lights.isStrobeOn() ? 1.0 : 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), traceId, simObject, "Failed to set strobe lights", Q_FUNC_INFO, "SimConnect_TransmitClientEvent::EventStrobesSet"); - // lights we need to toggle - // (potential risk with quickly changing values that we accidentally toggle back, also we need the light - // state before we can toggle) - this->sendToggledLightsToSimulator(simObject, lights); + const HRESULT hr6 = + this->logAndTraceSendId(SimConnect_TransmitClientEvent( + m_hSimConnect, objectId, EventTaxiLightsSet, lights.isTaxiOn() ? 1.0 : 0.0, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed to set taxi lights", Q_FUNC_INFO, + "SimConnect_TransmitClientEvent::EventTaxiLightsSet"); + + const HRESULT hr7 = + this->logAndTraceSendId(SimConnect_TransmitClientEvent( + m_hSimConnect, objectId, EventNavLightsSet, lights.isNavOn() ? 1.0 : 0.0, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed to set nav lights", Q_FUNC_INFO, + "SimConnect_TransmitClientEvent::EventNavLightsSet"); + + const HRESULT hr8 = + this->logAndTraceSendId(SimConnect_TransmitClientEvent( + m_hSimConnect, objectId, EventLogoLightsSet, lights.isLogoOn() ? 1.0 : 0.0, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed to set logo lights", Q_FUNC_INFO, + "SimConnect_TransmitClientEvent::EventLogoLightsSet"); + + const HRESULT hr9 = this->logAndTraceSendId( + SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventRecognitionLightsSet, + lights.isRecognitionOn() ? 1.0 : 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed to set recognitione lights", Q_FUNC_INFO, + "SimConnect_TransmitClientEvent::EventRecognitionLightsSet"); + + const HRESULT hr10 = + this->logAndTraceSendId(SimConnect_TransmitClientEvent( + m_hSimConnect, objectId, EventCabinLightsSet, lights.isCabinOn() ? 1.0 : 0.0, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed to set cabin lights", Q_FUNC_INFO, + "SimConnect_TransmitClientEvent::EventCabinLightsSet"); + + const HRESULT hr11 = + this->logAndTraceSendId(SimConnect_TransmitClientEvent( + m_hSimConnect, objectId, EventBeaconLightsSet, lights.isBeaconOn() ? 1.0 : 0.0, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed to set beacon lights", Q_FUNC_INFO, + "SimConnect_TransmitClientEvent::EventBeaconLightsSet"); + + const HRESULT hr12 = + this->logAndTraceSendId(SimConnect_TransmitClientEvent( + m_hSimConnect, objectId, EventWingLightsSet, lights.isWingOn() ? 1.0 : 0.0, + SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + traceId, simObject, "Failed to set wing lights", Q_FUNC_INFO, + "SimConnect_TransmitClientEvent::EventWingLightsSet"); // done - return isOk(hr1, hr2, hr3, hr4); + return isOk(hr1, hr2, hr3, (hr4 & hr5 & hr6 & hr7 & hr8 & hr9 & hr10 & hr11 & hr12)); } bool CSimulatorMsfs2024::sendRemoteAircraftAtcDataToSimulator(const CSimConnectObject &simObject) @@ -2423,104 +2481,107 @@ namespace swift::simplugin::msfs2024common return isOk(hr); } - void CSimulatorMsfs2024::sendToggledLightsToSimulator(const CSimConnectObject &simObj, - const CAircraftLights &lightsWanted, bool force) - { - if (!simObj.isReadyToSend()) { return; } // stale + // TODO TZ under investigation, toggling lights seems to be unreliable. The settings mentioned above can be used + // directly. void CSimulatorMsfs2024::sendToggledLightsToSimulator(const CSimConnectObject &simObj, + // const CAircraftLights &lightsWanted, bool force) + //{ + // if (!simObj.isReadyToSend()) { return; } // stale - const CAircraftLights lightsIsState = simObj.getCurrentLightsInSimulator(); - if (lightsWanted == lightsIsState) { return; } - if (!force && lightsWanted == simObj.getLightsAsSent()) { return; } - const CCallsign callsign(simObj.getCallsign()); + // const CAircraftLights lightsIsState = simObj.getCurrentLightsInSimulator(); + // if (lightsWanted == lightsIsState) { return; } + // if (!force && lightsWanted == simObj.getLightsAsSent()) { return; } + // const CCallsign callsign(simObj.getCallsign()); - // Update data - if (m_simConnectObjects.contains(callsign)) - { - CSimConnectObject &simObjToUpdate = m_simConnectObjects[callsign]; - simObjToUpdate.setLightsAsSent(lightsWanted); - } + // // Update data + // if (m_simConnectObjects.contains(callsign)) + // { + // CSimConnectObject &simObjToUpdate = m_simConnectObjects[callsign]; + // simObjToUpdate.setLightsAsSent(lightsWanted); + // } - // state available, then I can toggle - if (!lightsIsState.isNull()) - { - const DWORD objectId = simObj.getObjectId(); - const bool trace = this->isTracingSendId(); + // // state available, then I can toggle + // if (!lightsIsState.isNull()) + // { + // const DWORD objectId = simObj.getObjectId(); + // const bool trace = this->isTracingSendId(); - if (lightsWanted.isTaxiOn() != lightsIsState.isTaxiOn()) - { - this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleTaxiLights, - 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, - SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), - trace, simObj, "Toggle taxi lights", Q_FUNC_INFO, "EventToggleTaxiLights"); - } - if (lightsWanted.isNavOn() != lightsIsState.isNavOn()) - { - this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleNavLights, - 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, - SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), - trace, simObj, "Toggle nav.lights", Q_FUNC_INFO, "EventToggleNavLights"); - } - if (lightsWanted.isBeaconOn() != lightsIsState.isBeaconOn()) - { - this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleBeaconLights, - 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, - SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), - trace, simObj, "Toggle becon lights", Q_FUNC_INFO, "EventToggleBeaconLights"); - } - if (lightsWanted.isLogoOn() != lightsIsState.isLogoOn()) - { - this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleLogoLights, - 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, - SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), - trace, simObj, "Toggle logo lights", Q_FUNC_INFO, "EventToggleLogoLights"); - } - if (lightsWanted.isRecognitionOn() != lightsIsState.isRecognitionOn()) - { - this->logAndTraceSendId( - SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleRecognitionLights, 0.0, - SIMCONNECT_GROUP_PRIORITY_HIGHEST, - SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), - trace, simObj, "Toggle recognition lights", Q_FUNC_INFO, "EventToggleRecognitionLights"); - } - if (lightsWanted.isCabinOn() != lightsIsState.isCabinOn()) - { - this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleCabinLights, - 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, - SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), - trace, simObj, "Toggle cabin lights", Q_FUNC_INFO, "EventToggleCabinLights"); - } - return; - } + // if (lightsWanted.isTaxiOn() != lightsIsState.isTaxiOn()) + // { + // this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleTaxiLights, + // 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + // SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + // trace, simObj, "Toggle taxi lights", Q_FUNC_INFO, "EventToggleTaxiLights"); + // } + // if (lightsWanted.isNavOn() != lightsIsState.isNavOn()) + // { + // this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleNavLights, + // 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + // SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + // trace, simObj, "Toggle nav.lights", Q_FUNC_INFO, "EventToggleNavLights"); + // } + // if (lightsWanted.isBeaconOn() != lightsIsState.isBeaconOn()) + // { + // this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, + // EventToggleBeaconLights, + // 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + // SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + // trace, simObj, "Toggle becon lights", Q_FUNC_INFO, "EventToggleBeaconLights"); + // } + // if (lightsWanted.isLogoOn() != lightsIsState.isLogoOn()) + // { + // this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleLogoLights, + // 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + // SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + // trace, simObj, "Toggle logo lights", Q_FUNC_INFO, "EventToggleLogoLights"); + // } + // if (lightsWanted.isRecognitionOn() != lightsIsState.isRecognitionOn()) + // { + // this->logAndTraceSendId( + // SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventToggleRecognitionLights, 0.0, + // SIMCONNECT_GROUP_PRIORITY_HIGHEST, + // SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + // trace, simObj, "Toggle recognition lights", Q_FUNC_INFO, "EventToggleRecognitionLights"); + // } + // if (lightsWanted.isCabinOn() != lightsIsState.isCabinOn()) + // { + // this->logAndTraceSendId(SimConnect_TransmitClientEvent(m_hSimConnect, objectId, + // EventToggleCabinLights, + // 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, + // SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY), + // trace, simObj, "Toggle cabin lights", Q_FUNC_INFO, "EventToggleCabinLights"); + // } + // return; + // } - // missing lights info from simulator so far - if (this->showDebugLogMessage()) - { - this->debugLogMessage(Q_FUNC_INFO, QStringLiteral("Missing light state in simulator for '%1', model '%2'") - .arg(callsign.asString(), simObj.getAircraftModelString())); - } + // // missing lights info from simulator so far + // if (this->showDebugLogMessage()) + // { + // this->debugLogMessage(Q_FUNC_INFO, QStringLiteral("Missing light state in simulator for '%1', model '%2'") + // .arg(callsign.asString(), simObj.getAircraftModelString())); + // } - const QPointer myself(this); - QTimer::singleShot(DeferResendingLights, this, [=] { - if (!myself) { return; } - if (!m_simConnectObjects.contains(callsign)) { return; } - const CSimConnectObject currentSimObject = m_simConnectObjects[callsign]; - if (!currentSimObject.isReadyToSend()) { return; } // stale - if (lightsWanted != currentSimObject.getLightsAsSent()) - { - return; - } // changed in between, so another call sendToggledLightsToSimulator is pending - if (this->showDebugLogMessage()) - { - this->debugLogMessage(Q_FUNC_INFO, QStringLiteral("Resending light state for '%1', model '%2'") - .arg(callsign.asString(), simObj.getAircraftModelString())); - } - this->sendToggledLightsToSimulator(currentSimObject, lightsWanted, true); - }); - } + // const QPointer myself(this); + // QTimer::singleShot(DeferResendingLights, this, [=] { + // if (!myself) { return; } + // if (!m_simConnectObjects.contains(callsign)) { return; } + // const CSimConnectObject currentSimObject = m_simConnectObjects[callsign]; + // if (!currentSimObject.isReadyToSend()) { return; } // stale + // if (lightsWanted != currentSimObject.getLightsAsSent()) + // { + // return; + // } // changed in between, so another call sendToggledLightsToSimulator is pending + // if (this->showDebugLogMessage()) + // { + // this->debugLogMessage(Q_FUNC_INFO, QStringLiteral("Resending light state for '%1', model '%2'") + // .arg(callsign.asString(), simObj.getAircraftModelString())); + // } + // this->sendToggledLightsToSimulator(currentSimObject, lightsWanted, true); + // }); + //} SIMCONNECT_DATA_INITPOSITION - CSimulatorMsfs2024::aircraftSituationToFsxPosition(const CAircraftSituation &situation, bool sendGnd, - bool forceUnderflowDetection, CStatusMessage *details) + CSimulatorMsfs2024::aircraftSituationToPosition(const CAircraftSituation &situation, bool sendGnd, + bool forceUnderflowDetection, CStatusMessage *details) { Q_ASSERT_X(!situation.isGeodeticHeightNull(), Q_FUNC_INFO, "Missing height (altitude)"); Q_ASSERT_X(!situation.isPositionNull(), Q_FUNC_INFO, "Missing position"); @@ -2583,7 +2644,7 @@ namespace swift::simplugin::msfs2024common // crosscheck if (CBuildConfig::isLocalDeveloperDebugBuild()) { - SWIFT_VERIFY_X(isValidFsxPosition(position), Q_FUNC_INFO, "Invalid FSX pos."); + SWIFT_VERIFY_X(isValidFsxPosition(position), Q_FUNC_INFO, "Invalid MSFS2024 pos."); } return position; @@ -3091,24 +3152,7 @@ namespace swift::simplugin::msfs2024common const QString connectedSimName = m_simulatorName.toLower().trimmed(); if (connectedSimName.isEmpty()) { return false; } - if (pluginSim.isP3D()) - { - // P3D drivers only works with P3D - return connectedSimName.contains("lockheed") || connectedSimName.contains("martin") || - connectedSimName.contains("p3d") || connectedSimName.contains("prepar"); - } - else if (pluginSim.isFSX()) - { - // FSX drivers only works with FSX - 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()) + if (pluginSim.isMSFS2024()) { // MSFS2024 drivers only works with MSFS2024 return connectedSimName.contains("sunrise"); diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024common.h b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h index 760c62992f..a54d340015 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024common.h +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h @@ -68,26 +68,27 @@ namespace swift::simplugin::msfs2024common EventSetTimeZuluHours, EventSetTimeZuluMinutes, // ------------ lights ------------- - EventLandingLightsOff, - EventLandinglightsOn, + // EventLandingLightsOff, + // EventLandinglightsOn, EventLandingLightsSet, - EventLandingLightsToggle, - EventPanelLightsOff, - EventPanelLightsOn, + // EventLandingLightsToggle, + // EventPanelLightsOff, + // EventPanelLightsOn, EventPanelLightsSet, - EventStrobesOff, - EventStrobesOn, + // EventStrobesOff, + // EventStrobesOn, EventStrobesSet, - EventStrobesToggle, - EventToggleBeaconLights, - EventToggleCabinLights, - EventToggleLogoLights, - EventToggleNavLights, - EventToggleRecognitionLights, - EventToggleTaxiLights, - EventToggleWingLights, + // EventStrobesToggle, + EventBeaconLightsSet, + EventCabinLightsSet, + EventLogoLightsSet, + EventNavLightsSet, + EventRecognitionLightsSet, + EventTaxiLightsSet, + EventWingLightsSet, // ------------- flaps ------------- EventFlapsSet, + EventGearSet, // ---------- end marker ----------- EventFSXEndMarker }; @@ -337,9 +338,9 @@ namespace swift::simplugin::msfs2024common //! Format conversion //! \note must be valid situation static SIMCONNECT_DATA_INITPOSITION - aircraftSituationToFsxPosition(const swift::misc::aviation::CAircraftSituation &situation, bool sendGnd = true, - bool forceUnderflowDetection = false, - swift::misc::CStatusMessage *details = nullptr); + 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 @@ -474,9 +475,9 @@ namespace swift::simplugin::msfs2024common //! Send lights to simulator (those which have to be toggled) //! \remark challenge here is that I can only sent those value if I have already obtained the current light //! state from simulator \param force send lights even if they appear to be the same - void sendToggledLightsToSimulator(const CSimConnectObject &simObject, - const swift::misc::aviation::CAircraftLights &lightsWanted, - bool force = false); + // void sendToggledLightsToSimulator(const CSimConnectObject &simObject, + // const swift::misc::aviation::CAircraftLights &lightsWanted, + // bool force = false); //! Call CSimulatorFsxCommon::updateRemoteAircraftFromSimulator asynchronously //! \remark do not to send SimConnect data in event loop diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp index 45e338812b..c245cfd744 100644 --- a/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp +++ b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp @@ -281,7 +281,7 @@ namespace swift::simplugin::msfs2024common { case CSimConnectDefinitions::RequestOwnAircraft: { - static_assert(sizeof(DataDefinitionOwnAircraft) == 45 * sizeof(double), + static_assert(sizeof(DataDefinitionOwnAircraft) == 50 * sizeof(double), "DataDefinitionOwnAircraft has an incorrect size."); const DataDefinitionOwnAircraft *ownAircaft = reinterpret_cast(&pObjData->dwData); @@ -333,7 +333,7 @@ namespace swift::simplugin::msfs2024common } // model else if (subRequest == CSimConnectDefinitions::SimObjectLights) { - static_assert(sizeof(DataDefinitionRemoteAircraftLights) == 8 * sizeof(double), + static_assert(sizeof(DataDefinitionRemoteAircraftLights) == 9 * sizeof(double), "DataDefinitionRemoteAircraftLights has an incorrect size."); const DataDefinitionRemoteAircraftLights *remoteAircraftLights = reinterpret_cast(&pObjData->dwData); @@ -374,11 +374,6 @@ namespace swift::simplugin::msfs2024common (SIMCONNECT_RECV_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST *)pData; switch (msg->dwRequestID) { - // case CSimConnectDefinitions::REQUEST_ALL: - // case CSimConnectDefinitions::REQUEST_USER: - // case CSimConnectDefinitions::REQUEST_BOAT: - // case CSimConnectDefinitions::REQUEST_GROUND: - // case CSimConnectDefinitions::REQUEST_ANIMAL: case CSimConnectDefinitions::REQUEST_AIRPLANE: case CSimConnectDefinitions::REQUEST_HELICOPTER: case CSimConnectDefinitions::REQUEST_HOT_AIR: simulatorMsfs2024->CacheSimObjectAndLiveries(msg); break; diff --git a/src/swiftdata/swiftdataapplication.cpp b/src/swiftdata/swiftdataapplication.cpp index 699f12ff14..8fb5b6a872 100644 --- a/src/swiftdata/swiftdataapplication.cpp +++ b/src/swiftdata/swiftdataapplication.cpp @@ -23,7 +23,6 @@ CSwiftDataApplication::CSwiftDataApplication() // this->addAudioOptions(); } -// TODO TZ remove commented code after testing CStatusMessageList CSwiftDataApplication::startHookIn() { Q_ASSERT_X(m_parsed, Q_FUNC_INFO, "Not yet parsed cmd line arguments"); @@ -33,59 +32,15 @@ CStatusMessageList CSwiftDataApplication::startHookIn() this->isParserOptionSet(m_cmdFacadeMode) ? this->getParserValue(m_cmdFacadeMode) : QString(); CoreModes::CoreMode coreMode = CoreModes::stringToCoreMode(coreModeStr); - //// Valid combination? - // if (!coreModeStr.isEmpty()) - //{ - // if (coreMode == CoreModes::Standalone && !dBusAddress.isEmpty()) - // { - // const CStatusMessage m = - // CStatusMessage(this, CLogCategories::validation()).error(u"Inconsistent pair DBus: '%1' and core: - // '%2'") - // << dBusAddress << coreModeStr; - // return CStatusMessageList(m); - // } - // } - - //// Implicit configuration CStatusMessageList msgs; - // if (!dBusAddress.isEmpty() && coreModeStr.isEmpty()) - //{ - // coreMode = CoreModes::Distributed; // default - // const CStatusMessage m = - // CStatusMessage(this, CLogCategories::validation()).info(u"No DBus address, setting core mode: '%1'") - // << CoreModes::coreModeToString(coreMode); - // msgs.push_back(m); - // } - // else if (dBusAddress.isEmpty() && coreMode == CoreModes::Distributed) - //{ - // dBusAddress = CDBusServer::sessionBusAddress(); // a possible default - // const CStatusMessage m = - // CStatusMessage(this, CLogCategories::validation()).info(u"Setting DBus address to '%1'") << dBusAddress; - // msgs.push_back(m); - // } CCoreFacadeConfig runtimeConfig = coreModeToCoreFacadeConfig(coreMode, dBusAddress); const CStatusMessageList contextMsgs = this->initContextsAndStartCoreFacade(runtimeConfig); - // const CStatusMessageList contextMsgs = { CStatusMessage(this, CLogCategories::validation()).info(u"TEST") }; msgs.push_back(contextMsgs); return contextMsgs; } -bool CSwiftDataApplication::parsingHookIn() -{ - // Parse core relevant arguments - // const QString dBusAddress(this->getCmdDBusAddressValue()); - // if (!dBusAddress.isEmpty()) - //{ - // // check if reachable - // if (!CDBusServer::isDBusAvailable(dBusAddress)) - // { - // this->cmdLineErrorMessage("DBus error", "DBus server at '" + dBusAddress + "' can not be reached"); - // return false; - // } - // } - return CGuiApplication::parsingHookIn(); -} +bool CSwiftDataApplication::parsingHookIn() { return CGuiApplication::parsingHookIn(); } CSwiftDataApplication *CSwiftDataApplication::instance() { From 87543a112951ae0d42e2b7f89b7e6a6f08f58ac6 Mon Sep 17 00:00:00 2001 From: tzobler Date: Mon, 17 Nov 2025 14:10:14 +0100 Subject: [PATCH 7/8] refactor: remove outdated code for FSC --- src/core/CMakeLists.txt | 2 - src/core/airspacemonitor.cpp | 88 +++++++------------------------- src/core/airspacemonitor.h | 2 - src/core/fsd/fsdclient.cpp | 33 +----------- src/core/fsd/fsdclient.h | 3 +- src/core/fsd/messagebase.h | 3 -- src/core/fsd/revbclientparts.cpp | 39 -------------- src/core/fsd/revbclientparts.h | 58 --------------------- 8 files changed, 20 insertions(+), 208 deletions(-) delete mode 100644 src/core/fsd/revbclientparts.cpp delete mode 100644 src/core/fsd/revbclientparts.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1a4f7e67f1..09e3ded483 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -170,8 +170,6 @@ add_library(core SHARED fsd/pong.h fsd/rehost.cpp fsd/rehost.h - fsd/revbclientparts.cpp - fsd/revbclientparts.h fsd/serializer.cpp fsd/serializer.h fsd/servererror.cpp diff --git a/src/core/airspacemonitor.cpp b/src/core/airspacemonitor.cpp index bd350fb8f7..f2bb48502e 100644 --- a/src/core/airspacemonitor.cpp +++ b/src/core/airspacemonitor.cpp @@ -90,8 +90,6 @@ namespace swift::core connect(m_fsdClient, &CFSDClient::serverResponseReceived, this, &CAirspaceMonitor::onServerReplyReceived); connect(m_fsdClient, &CFSDClient::aircraftConfigReceived, this, &CAirspaceMonitor::onAircraftConfigReceived); connect(m_fsdClient, &CFSDClient::connectionStatusChanged, this, &CAirspaceMonitor::onConnectionStatusChanged); - connect(m_fsdClient, &CFSDClient::revbAircraftConfigReceived, this, - &CAirspaceMonitor::onRevBAircraftConfigReceived); Q_ASSERT_X(sApp && sApp->hasWebDataServices(), Q_FUNC_INFO, "Missing data reader"); @@ -546,13 +544,19 @@ namespace swift::core void CAirspaceMonitor::sendReadyForModelMatching(const CCallsign &callsign, MatchingReadinessFlag rf) { + if (!this->isConnectedAndNotShuttingDown()) { return; } Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign"); // TODO TZ remove when testing is done - CLogMessage(this).info(u"CAirspaceMonitor::sendReadyForModelMatching " - u"callsign %1 Flag %2 ") - << callsign << rf; + // CLogMessage(this).info(u"CAirspaceMonitor::sendReadyForModelMatching " + // u"callsign %1 Flag %2 ") + // << callsign << rf; + + CStatusMessageList reverseLookupMessages; + CCallsign::addLogDetailsToList(&reverseLookupMessages, callsign, + QStringLiteral("CAirspaceMonitor::sendReadyForModelMatching Flag: %1").arg(rf), + CAirspaceMonitor::getLogCategories()); // TODO remove // set flag and init ts @@ -674,6 +678,14 @@ namespace swift::core // normally we should never get here CLogMessage(this).info(u"Verified '%1' again, has ICAO codes, ready for matching!") << callsign; + + // TODO TZ remove when testing is done + CStatusMessageList reverseLookupMessages; + CCallsign::addLogDetailsToList(&reverseLookupMessages, callsign, + QStringLiteral("CAirspaceMonitor::verifyReceivedIcaoData"), + CAirspaceMonitor::getLogCategories()); + // end TZ remove + this->sendReadyForModelMatching(callsign, Verified); } @@ -837,7 +849,7 @@ namespace swift::core usedModelString.clear(); CCallsign::addLogDetailsToList( pReverseLookupMessages, callsign, - QStringLiteral("FsInn modelstring '%1' ignored because of setuo").arg(modelString)); + QStringLiteral("FsInn modelstring '%1' ignored because of setup").arg(modelString)); } else if (!CAircraftMatcher::isKnownModelString(modelString, callsign, pReverseLookupMessages)) { @@ -1481,70 +1493,6 @@ namespace swift::core this->updateAircraftInRange(callsign, vm); } - // TODO TZ I think, we can remove this method in future, as we have now longer IVAO supported protocols - void CAirspaceMonitor::onRevBAircraftConfigReceived(const CCallsign &callsign, const QString &config, - qint64 currentOffsetMs) - { - - Q_ASSERT(CThreadUtils::isInThisThread(this)); - SWIFT_AUDIT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Need callsign"); - if (callsign.isEmpty()) { return; } - - unsigned long pp = 0; - bool ok {}; - pp = config.toULong(&ok, 10); - - bool gear = (pp & 1U); - bool landLight = (pp & 2U); - bool navLight = (pp & 4U); - bool strobeLight = (pp & 8U); - bool beaconLight = (pp & 16U); - bool taxiLight = (pp & 32U); - bool engine1Running = (pp & 64U); - bool engine2Running = (pp & 128U); - bool engine3Running = (pp & 256U); - bool engine4Running = (pp & 512U); - - // CLogMessage(this).info(u"taxiLight %1 landLight %2 beaconLight %3 strobeLight %4 gear %5") << taxiLight << - // landLight << beaconLight << strobeLight << gear; CLogMessage(this).info(u"engine1Running %1 engine2Running %2 - // engine3Running %3 engine4Running %4") << engine1Running << engine2Running << engine3Running << - // engine4Running; - - CAircraftParts aircraftparts; - aircraftparts.setGearDown(gear); - - CAircraftLights lights; - lights.setStrobeOn(strobeLight); - lights.setLandingOn(landLight); - lights.setTaxiOn(taxiLight); - lights.setBeaconOn(beaconLight); - lights.setNavOn(navLight); - aircraftparts.setLights(lights); - - CAircraftEngineList engines; - engines.initEngines(4, false); - engines.setEngineOn(1, engine1Running); - engines.setEngineOn(2, engine2Running); - engines.setEngineOn(3, engine3Running); - engines.setEngineOn(4, engine4Running); - aircraftparts.setEngines(engines); - - // make sure in any case right time and correct details - aircraftparts.setCurrentUtcTime(); - aircraftparts.setTimeOffsetMs(currentOffsetMs); - aircraftparts.setPartsDetails(CAircraftParts::FSDAircraftParts); - - // store parts - this->storeAircraftParts(callsign, aircraftparts, true); - - // update client capability - CClient client = this->getClientOrDefaultForCallsign(callsign); - client.setUserCallsign(callsign); // make valid by setting a callsign - if (client.hasCapability(CClient::FsdWithAircraftConfig)) { return; } - client.addCapability(CClient::FsdWithAircraftConfig); - this->setOtherClient(client); - } - void CAirspaceMonitor::onAircraftConfigReceived(const CCallsign &callsign, const QJsonObject &jsonObject, qint64 currentOffsetMs) { diff --git a/src/core/airspacemonitor.h b/src/core/airspacemonitor.h index 94b2e558ec..978b9c462b 100644 --- a/src/core/airspacemonitor.h +++ b/src/core/airspacemonitor.h @@ -473,8 +473,6 @@ namespace swift::core const QString &aircraftIcao, const QString &airlineIcao); void onConnectionStatusChanged(swift::misc::network::CConnectionStatus oldStatus, swift::misc::network::CConnectionStatus newStatus); - void onRevBAircraftConfigReceived(const swift::misc::aviation::CCallsign &callsign, const QString &config, - qint64 currentOffsetMs); }; } // namespace swift::core diff --git a/src/core/fsd/fsdclient.cpp b/src/core/fsd/fsdclient.cpp index 156f27e3a2..50f9007bfd 100644 --- a/src/core/fsd/fsdclient.cpp +++ b/src/core/fsd/fsdclient.cpp @@ -34,7 +34,6 @@ #include "core/fsd/planeinformationfsinn.h" #include "core/fsd/pong.h" #include "core/fsd/rehost.h" -#include "core/fsd/revbclientparts.h" #include "core/fsd/serializer.h" #include "core/fsd/servererror.h" #include "core/fsd/textmessage.h" @@ -1078,16 +1077,6 @@ namespace swift::core::fsd // Euroscope m_messageTypeMapping["SIMDATA"] = MessageType::EuroscopeSimData; - - // IVAO only - // Ref: https://github.com/DemonRem/X-IvAP/blob/1b0a14880532a0f5c8fe84be44e462c6892a5596/src/XIvAp/FSDprotocol.h - m_messageTypeMapping["!R"] = MessageType::RegistrationInfo; - m_messageTypeMapping["-MD"] = MessageType::RevBClientParts; - m_messageTypeMapping["-PD"] = MessageType::RevBPilotDescription; // not handled, to avoid error messages - - // IVAO parts - // https://discordapp.com/channels/539048679160676382/695961646992195644/707915838845485187 - // https://github.com/swift-project/pilotclient/wiki/Knowledgebase-Simulation:-IVAO-parts } void CFSDClient::handleAtcDataUpdate(const QStringList &tokens) @@ -1620,23 +1609,6 @@ namespace swift::core::fsd if (serverError.isFatalError()) { disconnectFromServer(); } } - void CFSDClient::handleRevBClientPartsPacket(const QStringList &tokens) - { - CLogMessage(this).debug(u"handleRevBClientPartsPacket"); - - const RevBClientParts RevBClientParts = RevBClientParts::fromTokens(tokens); - const CCallsign callsign(RevBClientParts.sender(), CCallsign::Aircraft); - - const bool inRange = isAircraftInRange(callsign); - - if (!inRange) { return; } // sort out all broadcasts we DO NOT NEED - if (!getSetupForServer().receiveAircraftParts()) { return; } - - const qint64 offsetTimeMs = currentOffsetTime(callsign); - emit revbAircraftConfigReceived(RevBClientParts.sender(), RevBClientParts.m_partsval1, offsetTimeMs); - CLogMessage(this).debug(u"Set Config at %1 ") << offsetTimeMs; - } - void CFSDClient::handleRehost(const QStringList &tokens) { const Rehost rehost = Rehost::fromTokens(tokens); @@ -2280,9 +2252,7 @@ namespace swift::core::fsd case MessageType::AddPilot: case MessageType::ServerHeartbeat: case MessageType::ProController: - case MessageType::ClientIdentification: - case MessageType::RegistrationInfo: - case MessageType::RevBPilotDescription: break; + case MessageType::ClientIdentification: break; // handled ones case MessageType::AtcDataUpdate: handleAtcDataUpdate(tokens); break; @@ -2305,7 +2275,6 @@ namespace swift::core::fsd case MessageType::ServerError: handleServerError(tokens); break; case MessageType::TextMessage: handleTextMessage(tokens); break; case MessageType::PilotClientCom: handleCustomPilotPacket(tokens); break; - case MessageType::RevBClientParts: handleRevBClientPartsPacket(tokens); break; case MessageType::VisualPilotDataUpdate: case MessageType::VisualPilotDataPeriodic: case MessageType::VisualPilotDataStopped: handleVisualPilotDataUpdate(tokens, messageType); break; diff --git a/src/core/fsd/fsdclient.h b/src/core/fsd/fsdclient.h index 498364bce7..31183116dc 100644 --- a/src/core/fsd/fsdclient.h +++ b/src/core/fsd/fsdclient.h @@ -313,7 +313,7 @@ namespace swift::core::fsd void planeInformationFsinnReceived(const swift::misc::aviation::CCallsign &callsign, const QString &airlineIcaoDesignator, const QString &aircraftDesignator, const QString &combinedAircraftType, const QString &modelString); - void revbAircraftConfigReceived(const QString &sender, const QString &config, qint64 currentOffsetTimeMs); + void muteRequestReceived(bool mute); //! @} @@ -474,7 +474,6 @@ namespace swift::core::fsd #ifdef SWIFT_VATSIM_SUPPORT void handleFsdIdentification(const QStringList &tokens); #endif - void handleRevBClientPartsPacket(const QStringList &tokens); void handleRehost(const QStringList &tokens); void handleMute(const QStringList &tokens); diff --git a/src/core/fsd/messagebase.h b/src/core/fsd/messagebase.h index 00515e98dc..959720df70 100644 --- a/src/core/fsd/messagebase.h +++ b/src/core/fsd/messagebase.h @@ -42,11 +42,8 @@ enum class MessageType Pong, ServerError, ServerHeartbeat, - RegistrationInfo, // IVAO only TextMessage, PilotClientCom, - RevBClientParts, // IVAO only - RevBPilotDescription, // -PD IVAO only not handled in swift Rehost, Mute, }; diff --git a/src/core/fsd/revbclientparts.cpp b/src/core/fsd/revbclientparts.cpp deleted file mode 100644 index 8f99323780..0000000000 --- a/src/core/fsd/revbclientparts.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-FileCopyrightText: Copyright (C) 2020 swift Project Community / Contributors -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 - -#include "core/fsd/revbclientparts.h" - -#include "core/fsd/serializer.h" -#include "misc/logmessage.h" - -namespace swift::core::fsd -{ - RevBClientParts::RevBClientParts() {} - - RevBClientParts::RevBClientParts(const QString &sender, const QString &partsval1, const QString &partsval2, - const QString &partsval3) - : MessageBase(sender), m_partsval1(partsval1), m_partsval2(partsval2), m_partsval3(partsval3) - - {} - - QStringList RevBClientParts::toTokens() const - { - QStringList tokens; - tokens.push_back(m_sender); - tokens.push_back(m_partsval1); - tokens.push_back(m_partsval2); - tokens.push_back(m_partsval3); - return tokens; - } - - RevBClientParts RevBClientParts::fromTokens(const QStringList &tokens) - { - if (tokens.size() < 4) - { - swift::misc::CLogMessage(static_cast(nullptr)).debug(u"Wrong number of arguments."); - return {}; - } - return RevBClientParts(tokens[0], tokens[1], tokens[2], tokens[3]); - } - -} // namespace swift::core::fsd diff --git a/src/core/fsd/revbclientparts.h b/src/core/fsd/revbclientparts.h deleted file mode 100644 index dd27483030..0000000000 --- a/src/core/fsd/revbclientparts.h +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-FileCopyrightText: Copyright (C) 2020 swift Project Community / Contributors -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 - -//! \file - -#ifndef SWIFT_CORE_FSD_REVBCLIENTPARTS_H -#define SWIFT_CORE_FSD_REVBCLIENTPARTS_H - -#include "core/fsd/enums.h" -#include "core/fsd/messagebase.h" - -namespace swift::core::fsd -{ - //! This packet is used to translate client’s parts from RevB IVAO -MD. - //! -MDMDN0104:262396:262396:262396 - //! - class SWIFT_CORE_EXPORT RevBClientParts : public MessageBase - { - public: - //! Constructor - RevBClientParts(const QString &sender, const QString &partsval1, const QString &partsval2, - const QString &partsval3); - - //! Message converted to tokens - QStringList toTokens() const; - - //! Construct from tokens - static RevBClientParts fromTokens(const QStringList &tokens); - - //! PDU identifier - static QString pdu() { return "-MD"; } - - //! @{ - //! Properties - ClientQueryType m_queryType = ClientQueryType::Unknown; - QStringList m_queryData; - QString m_partsval1; - QString m_partsval2; - QString m_partsval3; - //! @} - - private: - RevBClientParts(); - }; - - //! Equal to operator - inline bool operator==(const RevBClientParts &lhs, const RevBClientParts &rhs) - { - return lhs.sender() == rhs.sender() && lhs.m_partsval1 == rhs.m_partsval1 && - lhs.m_partsval2 == rhs.m_partsval2 && lhs.m_partsval3 == rhs.m_partsval3; - } - - //! Not equal to operator - inline bool operator!=(const RevBClientParts &lhs, const RevBClientParts &rhs) { return !(lhs == rhs); } - -} // namespace swift::core::fsd - -#endif // SWIFT_CORE_FSD_REVBCLIENTPARTS_H From 6b953346196346ea8c6a5d0ded12deec347ee6d8 Mon Sep 17 00:00:00 2001 From: tzobler Date: Fri, 21 Nov 2025 14:48:49 +0100 Subject: [PATCH 8/8] fix: remove unnecessary code --- src/misc/simulation/msfs2024/simconnectutilities.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/misc/simulation/msfs2024/simconnectutilities.cpp b/src/misc/simulation/msfs2024/simconnectutilities.cpp index c4cc398c37..2f57cb08fa 100644 --- a/src/misc/simulation/msfs2024/simconnectutilities.cpp +++ b/src/misc/simulation/msfs2024/simconnectutilities.cpp @@ -15,8 +15,6 @@ using namespace swift::misc::aviation; namespace swift::misc::simulation::msfs2024 { - CSimConnectUtilities::CSimConnectUtilities() {} - QString CSimConnectUtilities::resolveEnumToString(const DWORD id, const char *enumName) { const int i = CSimConnectUtilities::staticMetaObject.indexOfEnumerator(enumName);