From 66acba9e87eab33e1154e0d5d5952c8fcb4cdf69 Mon Sep 17 00:00:00 2001
From: tzobler
Date: Sat, 31 Jan 2026 12:38:10 +0100
Subject: [PATCH] feat: enginepower implemented for fsxcommon
---
src/core/context/contextsimulatorimpl.cpp | 2 +-
src/core/db/databaseutils.cpp | 4 +
src/core/modelsetbuilder.cpp | 5 +-
src/core/modelsetbuilder.h | 3 +-
src/gui/components/dbownmodelscomponent.cpp | 19 +
src/gui/components/dbownmodelscomponent.h | 9 +-
src/gui/components/mappingcomponent.cpp | 7 +-
src/gui/components/mappingcomponent.ui | 705 ++--
src/gui/components/modelbrowsercomponent.ui | 657 ++--
.../settingssimulatorbasicscomponent.cpp | 120 +-
.../settingssimulatorbasicscomponent.ui | 457 ++-
src/gui/editors/aircraftpartsform.cpp | 66 +-
src/gui/editors/aircraftpartsform.ui | 704 ++--
src/misc/CMakeLists.txt | 4 +
src/misc/aviation/aircraftengine.cpp | 11 +-
src/misc/aviation/aircraftengine.h | 12 +-
src/misc/aviation/aircraftenginelist.cpp | 28 +-
src/misc/aviation/aircraftenginelist.h | 6 +-
src/misc/simulation/aircraftmodellist.cpp | 18 +-
src/misc/simulation/aircraftmodellist.h | 3 +-
src/misc/simulation/aircraftmodelloader.cpp | 14 +-
.../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/interpolation/interpolator.cpp | 4 +-
.../msfs2024/aircraftmodelloadermsfs2024.cpp | 105 +
.../msfs2024/aircraftmodelloadermsfs2024.h | 44 +
.../msfs2024/simconnectutilities.cpp | 73 +
.../simulation/msfs2024/simconnectutilities.h | 204 ++
.../simulation/settings/simulatorsettings.cpp | 12 +-
.../simulation/settings/simulatorsettings.h | 21 +-
src/misc/test/testserviceinterface.cpp | 2 +-
src/plugins/simulator/CMakeLists.txt | 2 +-
.../flightgear/simulatorflightgear.cpp | 3 +-
.../fsxcommon/simconnectdatadefinition.cpp | 159 +-
.../fsxcommon/simconnectdatadefinition.h | 39 +-
.../simulator/fsxcommon/simconnectsymbols.cpp | 31 -
.../simulator/fsxcommon/simconnectsymbols.h | 2 -
.../simulator/fsxcommon/simconnectwindows.h | 4 +-
.../fsxcommon/simulatorfsxcommon.cpp | 11 +-
.../fsxcommon/simulatorfsxsimconnectproc.cpp | 2 +-
src/plugins/simulator/msfs2024/CMakeLists.txt | 12 +-
.../simulator/msfs2024/msfs2024export.h | 26 +
.../simconnectdatadefinitionmsfs2024.cpp | 665 ++++
.../simconnectdatadefinitionmsfs2024.h | 413 +++
.../msfs2024/simconnectobjectmsfs2024.cpp | 516 +++
.../msfs2024/simconnectobjectmsfs2024.h | 440 +++
.../msfs2024/simconnectsymbolsmsfs2024.cpp | 585 ++++
.../msfs2024/simconnectsymbolsmsfs2024.h | 15 +
.../msfs2024/simconnectwindowsmsfs2024.h | 28 +
.../simulator/msfs2024/simulatormsfs2024.cpp | 10 +-
.../simulator/msfs2024/simulatormsfs2024.h | 16 +-
.../msfs2024/simulatormsfs2024common.cpp | 3101 +++++++++++++++++
.../msfs2024/simulatormsfs2024common.h | 762 ++++
.../simulatormsfs2024simconnectproc.cpp | 426 +++
.../simulator/xplane/simulatorxplane.cpp | 3 +-
src/xswiftbus/xplanemp2 | 2 +-
.../testaircraftparts/testaircraftparts.cpp | 2 +-
.../testinterpolatorlinear.cpp | 3 +-
.../testinterpolatorparts.cpp | 3 +-
63 files changed, 9316 insertions(+), 1334 deletions(-)
create mode 100644 src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp
create mode 100644 src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.h
create mode 100644 src/misc/simulation/msfs2024/simconnectutilities.cpp
create mode 100644 src/misc/simulation/msfs2024/simconnectutilities.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
diff --git a/src/core/context/contextsimulatorimpl.cpp b/src/core/context/contextsimulatorimpl.cpp
index f2fc105c0..2a2c120d2 100644
--- a/src/core/context/contextsimulatorimpl.cpp
+++ b/src/core/context/contextsimulatorimpl.cpp
@@ -241,7 +241,7 @@ namespace swift::core::context
{
Q_ASSERT_X(simulator.isSingleSimulator(), Q_FUNC_INFO, "Need single simulator");
if (isDebugEnabled()) { CLogMessage(this, CLogCategories::contextSlot()).debug() << Q_FUNC_INFO; }
- if (this->isSimulatorAvailable()) { return; } // if a plugin is loaded, do ignore this
+ if (this->isSimulatorAvailable() && !simulator.isMSFS2024()) return; // if a plugin is loaded, do ignore this
m_modelSetSimulator.set(simulator);
const CAircraftModelList models = this->getModelSet(); // cache synced
m_aircraftMatcher.setModelSet(models, simulator, false);
diff --git a/src/core/db/databaseutils.cpp b/src/core/db/databaseutils.cpp
index cf53239cd..8395658f8 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 2cbe84325..40f8739b8 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(ShowAllInstalledModels))
+ // 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 c85137707..530047f1f 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,
+ ShowAllInstalledModels = 1 << 6,
};
Q_DECLARE_FLAGS(Builder, BuilderFlag)
diff --git a/src/gui/components/dbownmodelscomponent.cpp b/src/gui/components/dbownmodelscomponent.cpp
index 91e81847d..25b5940de 100644
--- a/src/gui/components/dbownmodelscomponent.cpp
+++ b/src/gui/components/dbownmodelscomponent.cpp
@@ -332,6 +332,22 @@ 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"Triiger loading models for %1 from SimConnect")
+ << simulator.toQString();
+ this->showOverlayHTMLMessage(msg, 2s);
+
+ return;
+ }
+
void CDbOwnModelsComponent::loadInstalledModels(const CSimulatorInfo &simulator,
IAircraftModelLoader::LoadMode mode,
const QStringList &modelDirectories)
@@ -512,6 +528,9 @@ namespace swift::gui::components
IAircraftModelLoader::LoadMode mode,
const QStringList &modelDirectories)
{
+ // TODO TZ add SimConnect loading
+ if (simulator.isMSFS2024()) this->loadInstalledModelsSimConnect(simulator, mode, modelDirectories);
+
this->loadInstalledModels(simulator, mode, modelDirectories);
}
diff --git a/src/gui/components/dbownmodelscomponent.h b/src/gui/components/dbownmodelscomponent.h
index 22f099d5b..3b7334246 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.cpp b/src/gui/components/mappingcomponent.cpp
index 246085534..e61b4d0a3 100644
--- a/src/gui/components/mappingcomponent.cpp
+++ b/src/gui/components/mappingcomponent.cpp
@@ -333,6 +333,8 @@ 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())
{
@@ -375,6 +377,7 @@ namespace swift::gui::components
}
CAircraftModel model(models.front());
+ // found more than one model?
if (models.size() > 1)
{
if (models.containsModelString(modelString))
@@ -391,8 +394,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.ui b/src/gui/components/mappingcomponent.ui
index f06bb5f7d..da52efbf9 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
-
+
+ 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
+
+
+
+
+
+
+
+
-
- -
-
-
- 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/modelbrowsercomponent.ui b/src/gui/components/modelbrowsercomponent.ui
index c5d21c398..5743ba3ec 100644
--- a/src/gui/components/modelbrowsercomponent.ui
+++ b/src/gui/components/modelbrowsercomponent.ui
@@ -1,337 +1,346 @@
- CModelBrowserComponent
-
-
-
- 0
- 0
- 343
- 523
-
-
-
- Model browser
-
-
-
- 3
-
-
- 3
-
-
- 3
-
-
- 3
-
- -
-
-
- 0
-
-
-
- Model and position
-
-
-
+ CModelBrowserComponent
+
+
+
+ 0
+ 0
+ 343
+ 523
+
+
+
+ Model browser
+
+
+
3
-
-
+
+
3
-
-
+
+
3
-
-
+
+
3
-
-
-
-
-
- Model
-
-
-
-
-
-
- QAbstractItemView::SingleSelection
-
-
- QAbstractItemView::SelectRows
-
-
- false
+
+ -
+
+
+ 0
+
+
+
+ Model and position
-
-
- -
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Model set info
-
-
-
- -
-
-
- load model set
-
-
-
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+ -
+
+
+ Model
+
+
+
-
+
+
+ QAbstractItemView::SingleSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Model set info
+
+
+
+ -
+
+
+ load model set
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Use
+
+
+
-
+
+
+ use parts
+
+
+ true
+
+
+
+ -
+
+
+ use PBH
+
+
+ true
+
+
+
+ -
+
+
+ use CG (vert.offset)
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ Relative position
+
+
+
-
+
+
+ -
+
+
+ set
+
+
+
+
+
+
+ -
+
+
+ Absolute position
+
+
+
-
+
+
+
+ 0
+ 100
+
+
+
+
+
+
+
-
-
-
+
+
+
+ PBH/Parts/CG
+
+
+ -
+
+
+ PBH
+
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
-
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+
+
+
+ -
+
+
+ Parts
+
+
+
-
+
+
+
+ 0
+ 125
+
+
+
+
+
+
+
+ -
+
+
+ CG/vertical offset
+
+
+
-
+
+
+ -
+
+
+ override CG
+
+
+
+
+
+
+
+
-
- -
-
-
- Use
-
-
-
-
-
-
- use parts
-
-
-
- -
-
-
- use PBH
-
-
-
- -
-
-
- use CG (vert.offset)
-
-
-
-
-
-
- -
-
-
- Relative position
-
-
-
-
-
-
- -
-
-
- set
-
-
-
-
-
-
- -
-
-
- Absolute position
-
-
-
-
-
-
-
- 0
- 100
-
-
-
-
-
-
-
-
-
-
-
- PBH/Parts/CG
-
-
- -
-
-
- PBH
-
-
-
- 3
-
-
- 3
-
-
- 3
-
-
- 3
-
-
-
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
-
-
-
- -
-
-
- Parts
-
-
-
-
-
-
-
- 0
- 125
-
-
-
-
-
-
-
- -
-
-
- CG/vertical offset
-
-
-
-
-
-
- -
-
-
- override CG
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- true
-
-
-
-
-
- true
-
-
+
+
+
-
+
+
+ true
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ remove
+
+
+
+ -
+
+
+ display
+
+
+
+
+
- -
-
-
- remove
-
-
-
- -
-
-
- display
-
-
-
-
-
-
-
-
-
-
- swift::gui::editors::CRelativeAircraftPosition
- QFrame
- gui/editors/relativeaircraftposition.h
- 1
-
-
- swift::gui::editors::CCoordinateForm
- QFrame
- gui/editors/coordinateform.h
- 1
-
-
- swift::gui::views::CAircraftModelView
- QTableView
- gui/views/aircraftmodelview.h
-
-
- swift::gui::editors::CAircraftPartsForm
- QFrame
- gui/editors/aircraftpartsform.h
- 1
-
-
- swift::gui::editors::CPbhsForm
- QFrame
-
- 1
-
-
-
- tw_Tab
- tvp_AircraftModels
- pb_LoadModelSet
- cb_UseParts
- cb_UsePBH
- cb_UseCG
- pb_SetRelativePosition
- le_Info
- le_ModelInfo
- pb_Remove
- pb_Display
- le_CG
- cb_OverrideCG
-
-
-
+
+
+
+
+ swift::gui::editors::CRelativeAircraftPosition
+ QFrame
+ gui/editors/relativeaircraftposition.h
+ 1
+
+
+ swift::gui::editors::CCoordinateForm
+ QFrame
+ gui/editors/coordinateform.h
+ 1
+
+
+ swift::gui::views::CAircraftModelView
+ QTableView
+ gui/views/aircraftmodelview.h
+
+
+ swift::gui::editors::CAircraftPartsForm
+ QFrame
+ gui/editors/aircraftpartsform.h
+ 1
+
+
+ swift::gui::editors::CPbhsForm
+ QFrame
+
+ 1
+
+
+
+ tw_Tab
+ tvp_AircraftModels
+ pb_LoadModelSet
+ cb_UseParts
+ cb_UsePBH
+ cb_UseCG
+ pb_SetRelativePosition
+ le_Info
+ le_ModelInfo
+ pb_Remove
+ pb_Display
+ le_CG
+ cb_OverrideCG
+
+
+
diff --git a/src/gui/components/settingssimulatorbasicscomponent.cpp b/src/gui/components/settingssimulatorbasicscomponent.cpp
index 50b0ac80a..97fb0ad05 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
- {
- const QString ms = m.join("\n");
- ui->pte_ModelDirectories->setPlaceholderText(ms);
- }
+ CSimulatorSettings m_generic = settings.getGenericSettings();
- const QStringList e = settings.getDefaultModelExcludeDirectoryPatterns();
- if (e.isEmpty()) { ui->pte_ExcludeDirectories->setPlaceholderText("Exclude directories"); }
+ // 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())
+ {
+ 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);
+ }
+ }
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 a34d86d8b..08f847500 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 "creating a model set".</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 "creating a model set".</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/aircraftpartsform.cpp b/src/gui/editors/aircraftpartsform.cpp
index e4ceaff2c..f6d7a4887 100644
--- a/src/gui/editors/aircraftpartsform.cpp
+++ b/src/gui/editors/aircraftpartsform.cpp
@@ -114,6 +114,16 @@ namespace swift::gui::editors
ui->cb_AircraftPartsEngine4->setChecked(on);
ui->cb_AircraftPartsEngine5->setChecked(on);
ui->cb_AircraftPartsEngine6->setChecked(on);
+ ui->cb_AircraftPartsEngine7->setChecked(on);
+ ui->cb_AircraftPartsEngine8->setChecked(on);
+ ui->sb_AircraftPartsEngine1Percentage->setValue(on ? 80 : 0);
+ ui->sb_AircraftPartsEngine2Percentage->setValue(on ? 80 : 0);
+ ui->sb_AircraftPartsEngine3Percentage->setValue(on ? 80 : 0);
+ ui->sb_AircraftPartsEngine4Percentage->setValue(on ? 80 : 0);
+ ui->sb_AircraftPartsEngine5Percentage->setValue(on ? 80 : 0);
+ ui->sb_AircraftPartsEngine6Percentage->setValue(on ? 80 : 0);
+ ui->sb_AircraftPartsEngine7Percentage->setValue(on ? 80 : 0);
+ ui->sb_AircraftPartsEngine8Percentage->setValue(on ? 80 : 0);
}
aviation::CAircraftParts CAircraftPartsForm::guiToAircraftParts() const
@@ -124,10 +134,48 @@ namespace swift::gui::editors
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(),
- ui->cb_AircraftPartsEngine5->isChecked(), ui->cb_AircraftPartsEngine6->isChecked() });
+
+ CAircraftEngineList engines;
+ engines.initEngines(8, false, 0); // 6 Engines, alle off, 0%
+
+ // engines.push_back(CAircraftEngine(1, ui->cb_AircraftPartsEngine1->isChecked(),
+ // ui->sb_AircraftPartsEngine1Percentage->value()));
+ // engines.push_back(CAircraftEngine(2, ui->cb_AircraftPartsEngine2->isChecked(),
+ // ui->sb_AircraftPartsEngine2Percentage->value()));
+ // engines.push_back(CAircraftEngine(3, ui->cb_AircraftPartsEngine3->isChecked(),
+ // ui->sb_AircraftPartsEngine3Percentage->value()));
+ // engines.push_back(CAircraftEngine(4, ui->cb_AircraftPartsEngine4->isChecked(),
+ // ui->sb_AircraftPartsEngine4Percentage->value()));
+ // engines.push_back(CAircraftEngine(5, ui->cb_AircraftPartsEngine5->isChecked(),
+ // ui->sb_AircraftPartsEngine5Percentage->value()));
+ // engines.push_back(CAircraftEngine(6, ui->cb_AircraftPartsEngine6->isChecked(),
+ // ui->sb_AircraftPartsEngine6Percentage->value()));
+ // engines.push_back(CAircraftEngine(6, ui->cb_AircraftPartsEngine6->isChecked(),
+ // ui->sb_AircraftPartsEngine6Percentage->value()));
+ // engines.push_back(CAircraftEngine(7, ui->cb_AircraftPartsEngine7->isChecked(),
+ // ui->sb_AircraftPartsEngine7Percentage->value()));
+ // engines.push_back(CAircraftEngine(8, ui->cb_AircraftPartsEngine8->isChecked(),
+ // ui->sb_AircraftPartsEngine8Percentage->value()));
+ // Set On/Off Status
+ engines.setEngineOn(1, ui->cb_AircraftPartsEngine1->isChecked());
+ engines.setEngineOn(2, ui->cb_AircraftPartsEngine2->isChecked());
+ engines.setEngineOn(3, ui->cb_AircraftPartsEngine3->isChecked());
+ engines.setEngineOn(4, ui->cb_AircraftPartsEngine4->isChecked());
+ engines.setEngineOn(5, ui->cb_AircraftPartsEngine5->isChecked());
+ engines.setEngineOn(6, ui->cb_AircraftPartsEngine6->isChecked());
+ engines.setEngineOn(7, ui->cb_AircraftPartsEngine7->isChecked());
+ engines.setEngineOn(8, ui->cb_AircraftPartsEngine8->isChecked());
+
+ // Setze Prozentsätze
+ engines.setEnginePower(1, ui->sb_AircraftPartsEngine1Percentage->value());
+ engines.setEnginePower(2, ui->sb_AircraftPartsEngine2Percentage->value());
+ engines.setEnginePower(3, ui->sb_AircraftPartsEngine3Percentage->value());
+ engines.setEnginePower(4, ui->sb_AircraftPartsEngine4Percentage->value());
+ engines.setEnginePower(5, ui->sb_AircraftPartsEngine5Percentage->value());
+ engines.setEnginePower(6, ui->sb_AircraftPartsEngine6Percentage->value());
+ engines.setEnginePower(7, ui->sb_AircraftPartsEngine7Percentage->value());
+ engines.setEnginePower(8, ui->sb_AircraftPartsEngine8Percentage->value());
+
const CAircraftParts parts(
lights, ui->cb_AircraftPartsGearDown->isChecked(), ui->sb_AircraftPartsFlapsPercentage->value(),
ui->cb_AircraftPartsSpoilers->isChecked(), engines, ui->cb_AircraftPartsIsOnGround->isChecked());
@@ -157,6 +205,16 @@ namespace swift::gui::editors
ui->cb_AircraftPartsEngine4->setChecked(engines.isEngineOn(4));
ui->cb_AircraftPartsEngine5->setChecked(engines.isEngineOn(5));
ui->cb_AircraftPartsEngine6->setChecked(engines.isEngineOn(6));
+ ui->cb_AircraftPartsEngine7->setChecked(engines.isEngineOn(7));
+ ui->cb_AircraftPartsEngine8->setChecked(engines.isEngineOn(8));
+ ui->sb_AircraftPartsEngine1Percentage->setValue(engines.getEnginePower(1));
+ ui->sb_AircraftPartsEngine2Percentage->setValue(engines.getEnginePower(2));
+ ui->sb_AircraftPartsEngine3Percentage->setValue(engines.getEnginePower(3));
+ ui->sb_AircraftPartsEngine4Percentage->setValue(engines.getEnginePower(4));
+ ui->sb_AircraftPartsEngine5Percentage->setValue(engines.getEnginePower(5));
+ ui->sb_AircraftPartsEngine6Percentage->setValue(engines.getEnginePower(6));
+ ui->sb_AircraftPartsEngine7Percentage->setValue(engines.getEnginePower(7));
+ ui->sb_AircraftPartsEngine8Percentage->setValue(engines.getEnginePower(8));
}
void CAircraftPartsForm::guiToJson()
diff --git a/src/gui/editors/aircraftpartsform.ui b/src/gui/editors/aircraftpartsform.ui
index 9d28ebb74..731008015 100644
--- a/src/gui/editors/aircraftpartsform.ui
+++ b/src/gui/editors/aircraftpartsform.ui
@@ -1,299 +1,443 @@
- CAircraftPartsForm
-
-
-
- 0
- 0
- 276
- 403
-
-
-
- Frame
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
- 3
-
-
- 3
-
-
- 3
-
-
- 3
-
- -
-
-
- Strobe
-
-
-
- -
-
-
- all off
-
-
-
- -
-
-
- Flaps %:
-
-
-
- -
-
-
- 100
-
-
- 5
-
-
-
- -
-
-
- Landing
-
-
-
-
- -
-
-
- Wing
-
-
-
- -
-
-
- Recognition
-
-
-
- -
-
-
- Cabin
-
-
-
-
-
- -
-
-
- Nav
-
-
-
- -
-
-
- to JSON
-
-
-
- -
-
-
- Gear down
-
-
-
- -
-
-
- Beacon
-
-
-
- -
-
-
- on ground
-
-
-
- -
-
-
- Lights:
-
-
-
- -
-
-
- Taxi
-
-
-
- -
-
-
- Spoilers
-
-
-
- -
-
-
- all off
-
-
-
- -
-
-
- all on
-
-
-
- -
-
-
- Logo
-
-
-
- -
-
-
- all on
-
-
-
- -
-
-
- -
-
-
- Engines:
-
-
-
- -
-
-
-
- 0
- 20
-
-
-
+ CAircraftPartsForm
+
+
+
+ 0
+ 0
+ 276
+ 403
+
+
+
+ Frame
+
+
QFrame::StyledPanel
-
-
+
+
QFrame::Raised
-
-
+
+
- 0
+ 3
- 0
+ 3
- 0
+ 3
- 0
+ 3
-
-
-
-
- 1
-
-
+
-
+
+
+ Strobe
+
+
- -
-
-
- 2
-
-
+
-
+
+
+ all off
+
+
- -
-
-
- 3
-
-
+
-
+
+
+ Flaps %:
+
+
- -
-
-
- 4
-
-
+
-
+
+
+ 100
+
+
+ 5
+
+
- -
-
-
- 5
-
-
+
-
+
+
+ Landing
+
+
- -
-
-
- 6
-
-
+
+
-
+
+
+ Wing
+
+
-
-
-
- -
-
-
- set
-
-
-
-
-
-
- sb_AircraftPartsFlapsPercentage
- pb_AircraftPartsUiToJson
- cb_AircraftPartsGearDown
- cb_AircraftPartsSpoilers
- cb_AircraftPartsIsOnGround
- pb_AircraftPartsLightsOn
- pb_AircraftPartsLightsOff
- cb_AircraftPartsLightsTaxi
- cb_AircraftPartsLightsNav
- cb_AircraftPartsLightsLanding
- cb_AircraftPartsLightsBeacon
- cb_AircraftPartsLightsStrobe
- cb_AircraftPartsLightsLogo
- pb_AircraftPartsEnginesOn
- pb_AircraftPartsEnginesOff
- cb_AircraftPartsEngine1
- cb_AircraftPartsEngine2
- cb_AircraftPartsEngine3
- cb_AircraftPartsEngine4
- cb_AircraftPartsEngine5
- cb_AircraftPartsEngine6
- te_AircraftPartsJson
- pb_Set
-
-
-
+ -
+
+
+ Recognition
+
+
+
+ -
+
+
+ Cabin
+
+
+
+
+
+ -
+
+
+ Nav
+
+
+
+ -
+
+
+ to JSON
+
+
+
+ -
+
+
+ Gear down
+
+
+ true
+
+
+
+ -
+
+
+ Beacon
+
+
+
+ -
+
+
+ on ground
+
+
+ true
+
+
+
+ -
+
+
+ Lights:
+
+
+
+ -
+
+
+ Taxi
+
+
+
+ -
+
+
+ Spoilers
+
+
+
+ -
+
+
+ all off
+
+
+
+ -
+
+
+ all on
+
+
+
+ -
+
+
+ Logo
+
+
+
+ -
+
+
+ all on
+
+
+
+ -
+
+
+ Engines:
+
+
+
+ -
+
+
+
+ 0
+ 20
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
-
+
+
+ 1
+
+
+
+ -
+
+
+ 2
+
+
+
+ -
+
+
+ 3
+
+
+
+ -
+
+
+ 4
+
+
+
+ -
+
+
+ 5
+
+
+
+ -
+
+
+ 6
+
+
+
+ -
+
+
+ 7
+
+
+
+ -
+
+
+ 8
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 20
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ 100
+
+
+ 7
+
+
+
+ -
+
+
+ 100
+
+
+ 8
+
+
+
+ -
+
+
+ 100
+
+
+ 9
+
+
+
+ -
+
+
+ 100
+
+
+ 7
+
+
+
+ -
+
+
+ 100
+
+
+ 10
+
+
+
+ -
+
+
+ 100
+
+
+ 11
+
+
+
+ -
+
+
+ 100
+
+
+ 11
+
+
+
+ -
+
+
+ 100
+
+
+ 11
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ -
+
+
+ set
+
+
+
+
+
+
+ sb_AircraftPartsFlapsPercentage
+ pb_AircraftPartsUiToJson
+ cb_AircraftPartsGearDown
+ cb_AircraftPartsSpoilers
+ cb_AircraftPartsIsOnGround
+ pb_AircraftPartsLightsOn
+ pb_AircraftPartsLightsOff
+ cb_AircraftPartsLightsTaxi
+ cb_AircraftPartsLightsNav
+ cb_AircraftPartsLightsLanding
+ cb_AircraftPartsLightsBeacon
+ cb_AircraftPartsLightsStrobe
+ cb_AircraftPartsLightsLogo
+ pb_AircraftPartsEnginesOn
+ pb_AircraftPartsEnginesOff
+ cb_AircraftPartsEngine1
+ cb_AircraftPartsEngine2
+ cb_AircraftPartsEngine3
+ cb_AircraftPartsEngine4
+ cb_AircraftPartsEngine5
+ cb_AircraftPartsEngine6
+ sb_AircraftPartsEngine1Percentage
+ sb_AircraftPartsEngine2Percentage
+ sb_AircraftPartsEngine3Percentage
+ sb_AircraftPartsEngine4Percentage
+ sb_AircraftPartsEngine5Percentage
+ sb_AircraftPartsEngine6Percentage
+ te_AircraftPartsJson
+ pb_Set
+
+
+
diff --git a/src/misc/CMakeLists.txt b/src/misc/CMakeLists.txt
index 6d0e075a9..07858420c 100644
--- a/src/misc/CMakeLists.txt
+++ b/src/misc/CMakeLists.txt
@@ -532,6 +532,10 @@ 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/msfs2024/simconnectutilities.cpp
+ simulation/msfs2024/simconnectutilities.h
simulation/fscommon/aircraftcfgentries.cpp
simulation/fscommon/aircraftcfgentries.h
simulation/fscommon/aircraftcfgentrieslist.cpp
diff --git a/src/misc/aviation/aircraftengine.cpp b/src/misc/aviation/aircraftengine.cpp
index c5828a7bc..642ef0933 100644
--- a/src/misc/aviation/aircraftengine.cpp
+++ b/src/misc/aviation/aircraftengine.cpp
@@ -11,7 +11,8 @@ SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::aviation, CAircraftEngine)
namespace swift::misc::aviation
{
- CAircraftEngine::CAircraftEngine(int number, bool on) : m_number(number), m_on(on)
+ CAircraftEngine::CAircraftEngine(int number, bool on, int enginePercentage)
+ : m_number(number), m_on(on), m_power(enginePercentage)
{
Q_ASSERT_X(number > 0, "CAircraftEngine", "Engine numbers have to be > 1");
}
@@ -22,6 +23,14 @@ namespace swift::misc::aviation
m_number = number;
}
+ void CAircraftEngine::setEnginePower(double power)
+ {
+ m_power = power;
+ if (!m_on) m_power = 0;
+ if (m_power > 100) m_power = 100;
+ if (m_power < 0) m_power = 0;
+ }
+
QString CAircraftEngine::convertToQString(bool i18n) const
{
Q_UNUSED(i18n);
diff --git a/src/misc/aviation/aircraftengine.h b/src/misc/aviation/aircraftengine.h
index da49cdc33..4bfeea50a 100644
--- a/src/misc/aviation/aircraftengine.h
+++ b/src/misc/aviation/aircraftengine.h
@@ -26,7 +26,9 @@ namespace swift::misc::aviation
//! Constructor
//! \remark numbers are 1 based!
- CAircraftEngine(int number, bool on);
+ // CAircraftEngine(int number, bool on);
+
+ CAircraftEngine(int number, bool on, int enginePower);
//! Get engine number
//! \remark numbers are 1 based!
@@ -42,17 +44,23 @@ namespace swift::misc::aviation
//! Set to on/off
void setOn(bool on) { m_on = on; }
+ //! Set engine percentage (0..100)
+ void setEnginePower(double percentage);
+ double getEnginePower() const { return m_power; }
+
//! \copydoc swift::misc::mixin::String::toQString
QString convertToQString(bool i18n = false) const;
private:
int m_number = 1;
bool m_on = true;
+ double m_power = 0.0;
SWIFT_METACLASS(
CAircraftEngine,
SWIFT_METAMEMBER(number, 0, DisabledForJson),
- SWIFT_METAMEMBER(on));
+ SWIFT_METAMEMBER(on),
+ SWIFT_METAMEMBER(power));
};
} // namespace swift::misc::aviation
diff --git a/src/misc/aviation/aircraftenginelist.cpp b/src/misc/aviation/aircraftenginelist.cpp
index 05267fb13..16e8b3e1f 100644
--- a/src/misc/aviation/aircraftenginelist.cpp
+++ b/src/misc/aviation/aircraftenginelist.cpp
@@ -15,7 +15,10 @@ namespace swift::misc::aviation
int no = 1; // engines 1 based
for (bool it : enginesOnOff)
{
- CAircraftEngine engine(no++, it);
+ CAircraftEngine engine;
+ engine.setNumber(no++);
+ engine.setOn(it);
+ engine.setEnginePower(it ? 80 : 0);
this->push_back(engine);
}
}
@@ -60,16 +63,35 @@ namespace swift::misc::aviation
}
}
- void CAircraftEngineList::initEngines(int engineNumber, bool on)
+ void CAircraftEngineList::initEngines(int engineNumber, bool on, int enginePercentage)
{
this->clear();
for (int e = 0; e < engineNumber; e++)
{
- const CAircraftEngine engine(e + 1, on);
+ const CAircraftEngine engine(e + 1, on, enginePercentage);
this->push_back(engine);
}
}
+ void CAircraftEngineList::setEnginePower(int engineNumber, int percentage)
+ {
+ Q_ASSERT(engineNumber > 0);
+ for (CAircraftEngine &engine : *this)
+ {
+ if (engine.getNumber() == engineNumber)
+ {
+ engine.setEnginePower(percentage);
+ break;
+ }
+ }
+ }
+
+ int CAircraftEngineList::getEnginePower(int engineNumber) const
+ {
+ Q_ASSERT(engineNumber > 0);
+ return this->getEngine(engineNumber).getEnginePower();
+ }
+
bool CAircraftEngineList::isAnyEngineOn() const { return this->contains(&CAircraftEngine::isOn, true); }
QJsonObject CAircraftEngineList::toJson() const
diff --git a/src/misc/aviation/aircraftenginelist.h b/src/misc/aviation/aircraftenginelist.h
index 2fd5dc3af..ac5c519a4 100644
--- a/src/misc/aviation/aircraftenginelist.h
+++ b/src/misc/aviation/aircraftenginelist.h
@@ -57,11 +57,15 @@ namespace swift::misc::aviation
void setEngines(const CAircraftEngine &engine, int engineNumber);
//! Init some engines
- void initEngines(int engineNumber, bool on);
+ void initEngines(int engineNumber, bool on, int enginePercentage);
//! Is any engine on?
bool isAnyEngineOn() const;
+ void setEnginePower(int engineNumber, int percentage);
+
+ int getEnginePower(int engineNumber) const;
+
//! \copydoc swift::misc::mixin::JsonByMetaClass::toJson
QJsonObject toJson() const;
diff --git a/src/misc/simulation/aircraftmodellist.cpp b/src/misc/simulation/aircraftmodellist.cpp
index e8c16e818..8dd3a58ba 100644
--- a/src/misc/simulation/aircraftmodellist.cpp
+++ b/src/misc/simulation/aircraftmodellist.cpp
@@ -725,12 +725,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;
}
@@ -843,7 +845,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;
}
@@ -1737,12 +1743,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 2046f21c1..b1ab05a18 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
diff --git a/src/misc/simulation/aircraftmodelloader.cpp b/src/misc/simulation/aircraftmodelloader.cpp
index a7bf4ccbf..c8cba5bcf 100644
--- a/src/misc/simulation/aircraftmodelloader.cpp
+++ b/src/misc/simulation/aircraftmodelloader.cpp
@@ -129,8 +129,17 @@ namespace swift::misc::simulation
return;
}
- // really load from disk?
- const QStringList modelDirs = this->getInitializedModelDirectories(modelDirectories, simulator);
+ // TODO TZ 2024: skip loading for MSFS2024?
+ QStringList modelDirs = { "", "" };
+ // 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,
@@ -141,6 +150,7 @@ namespace swift::misc::simulation
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 f81c7e196..ebf5c169e 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 7682dc04e..be8a908b0 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 3a7c23ad1..dc03414c1 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 {}; // 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 9850f74bf..6ff000f36 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 e8c8d1e0d..bd14ae5eb 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 07bfa55fc..7cde5deb1 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/interpolation/interpolator.cpp b/src/misc/simulation/interpolation/interpolator.cpp
index 79e9a8267..df9ec6753 100644
--- a/src/misc/simulation/interpolation/interpolator.cpp
+++ b/src/misc/simulation/interpolation/interpolator.cpp
@@ -494,7 +494,7 @@ namespace swift::misc::simulation
do {
// set some reasonable values
const bool isOnGround = situation.isOnGround();
- engines.initEngines(engineCount, !isOnGround || situation.isMoving());
+ engines.initEngines(engineCount, !isOnGround || situation.isMoving(), (!isOnGround || situation.isMoving()) ? 100 : 0);
parts.setGearDown(isOnGround);
parts.setSpoilersOut(false);
parts.setEngines(engines);
@@ -530,7 +530,7 @@ namespace swift::misc::simulation
if (details) { *details = QStringLiteral("no ground info"); }
// no idea if on ground or not
- engines.initEngines(engineCount, true);
+ engines.initEngines(engineCount, true , 100);
parts.setEngines(engines);
parts.setGearDown(true);
parts.setSpoilersOut(false);
diff --git a/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp b/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp
new file mode 100644
index 000000000..1d27b6aaf
--- /dev/null
+++ b/src/misc/simulation/msfs2024/aircraftmodelloadermsfs2024.cpp
@@ -0,0 +1,105 @@
+// 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
+ // still no idea how to do that
+ 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);
+
+ m_parserWorker =
+ CWorker::fromTask(this, "CAircraftModelLoaderMsfs2024::performParsing", [this, 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 000000000..a7dd37cc0
--- /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/msfs2024/simconnectutilities.cpp b/src/misc/simulation/msfs2024/simconnectutilities.cpp
new file mode 100644
index 000000000..2f57cb08f
--- /dev/null
+++ b/src/misc/simulation/msfs2024/simconnectutilities.cpp
@@ -0,0 +1,73 @@
+// 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
+{
+ 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 000000000..f2c2cbb95
--- /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/misc/simulation/settings/simulatorsettings.cpp b/src/misc/simulation/settings/simulatorsettings.cpp
index 1f1c3e553..c393b91d6 100644
--- a/src/misc/simulation/settings/simulatorsettings.cpp
+++ b/src/misc/simulation/settings/simulatorsettings.cpp
@@ -152,6 +152,10 @@ namespace swift::misc::simulation::settings
}
}
+ void CSimulatorSettings::setPropertyModelSet(bool value) { m_modelSet = value; }
+ void CSimulatorSettings::setPropertyWithDbEntry(bool value) { m_withDbEntry = value; }
+ void CSimulatorSettings::setPropertyDistributorFiltered(bool value) { m_distributorFiltered = value; }
+
void CSimulatorSettings::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
{
if (index.isMyself())
@@ -617,7 +621,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);
}
@@ -692,9 +696,9 @@ namespace swift::misc::simulation::settings
}
case CSimulatorInfo::MSFS2024:
{
- static const QString msfs2024 =
- CFileUtils::normalizeFilePathToQtStandard(CFsDirectories::msfs2024PackagesDir());
- if (msfs2024.isEmpty()) { return e; }
+ // msfs2024 uses no model directories but uses the field "packages directory" for filtering modelstrings
+ // Asterix stands for everything == no filtering
+ static const QString msfs2024 = "*";
static const QStringList md { msfs2024 };
return md;
}
diff --git a/src/misc/simulation/settings/simulatorsettings.h b/src/misc/simulation/settings/simulatorsettings.h
index 056635ef7..0b38e267d 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() const { return m_withDbEntry; }
+ bool getPropertyModelSet() const { return m_modelSet; }
+ bool getPropertyDistributorFiltered() const { 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/test/testserviceinterface.cpp b/src/misc/test/testserviceinterface.cpp
index 2139f4f20..91b531e2e 100644
--- a/src/misc/test/testserviceinterface.cpp
+++ b/src/misc/test/testserviceinterface.cpp
@@ -89,7 +89,7 @@ namespace swift::misc::test
ok = pingCompare(lights, lightsPing, out, verbose, errors);
if (verbose) { out << "Pinged lights via interface" << errorInfo(ok) << Qt::endl; }
- const CAircraftEngine engine(2, false);
+ const CAircraftEngine engine(2, false, 0);
const CAircraftEngine enginePing = testServiceInterface.pingAircraftEngine(engine);
ok = pingCompare(engine, enginePing, out, verbose, errors);
if (verbose) { out << "Pinged engine via interface" << errorInfo(ok) << Qt::endl; }
diff --git a/src/plugins/simulator/CMakeLists.txt b/src/plugins/simulator/CMakeLists.txt
index 4572f5131..17c1c4039 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/flightgear/simulatorflightgear.cpp b/src/plugins/simulator/flightgear/simulatorflightgear.cpp
index 8f7f0e9e0..f1c138987 100644
--- a/src/plugins/simulator/flightgear/simulatorflightgear.cpp
+++ b/src/plugins/simulator/flightgear/simulatorflightgear.cpp
@@ -281,7 +281,8 @@ namespace swift::simplugin::flightgear
// Engine number start counting at 1
// We consider the engine running when N1 is bigger than 5 %
CAircraftEngine engine { engineNumber + 1,
- m_flightgearData.enginesN1Percentage.at(engineNumber) > 5.0 };
+ m_flightgearData.enginesN1Percentage.at(engineNumber) > 5.0,
+ static_cast(m_flightgearData.enginesN1Percentage.at(engineNumber)) };
engines.push_back(engine);
}
diff --git a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp
index 1ee57e99f..c0c9f6574 100644
--- a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp
+++ b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.cpp
@@ -82,7 +82,6 @@ namespace swift::simplugin::fsxcommon
hr += initSimulatorEnvironment(hSimConnect);
hr += initSbDataArea(hSimConnect);
if (simInfo.isMSFS()) { hr += initMSFSTransponder(hSimConnect); }
- if (simInfo.isMSFS2024()) { hr += initMSFS2024Transponder(hSimConnect); }
return hr;
}
@@ -126,6 +125,13 @@ namespace swift::simplugin::fsxcommon
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,
@@ -167,6 +173,32 @@ namespace swift::simplugin::fsxcommon
"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,
+ "GENERAL ENG COMBUSTION:7", "Bool");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG COMBUSTION:8", "Bool");
+
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:1", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:2", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:3", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:4", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:5", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:6", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:7", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:8", "percent");
+
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "VELOCITY WORLD X",
"Feet per second");
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft, "VELOCITY WORLD Y",
@@ -228,8 +260,32 @@ namespace swift::simplugin::fsxcommon
"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::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG COMBUSTION:7", "Bool");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG COMBUSTION:8", "Bool");
+
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:1", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:2", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:3", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:4", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:5", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:6", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:7", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:8", "percent");
- // Lights (other definition)
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraftTitle, "TITLE",
nullptr, SIMCONNECT_DATATYPE_STRING256);
@@ -245,12 +301,12 @@ namespace swift::simplugin::fsxcommon
"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))
{
@@ -423,22 +479,6 @@ 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;
- }
-
DataDefinitionRemoteAircraftPartsWithoutLights::DataDefinitionRemoteAircraftPartsWithoutLights()
{
this->resetToInvalid();
@@ -455,30 +495,74 @@ namespace swift::simplugin::fsxcommon
{
return std::tie(flapsLeadingEdgeLeftPercent, flapsLeadingEdgeRightPercent, flapsTrailingEdgeLeftPercent,
flapsTrailingEdgeRightPercent, gearHandlePosition, spoilersHandlePosition, engine1Combustion,
- engine2Combustion, engine3Combustion, engine4Combustion) ==
+ engine2Combustion, engine3Combustion, engine4Combustion, engine5Combustion, engine6Combustion,
+ engine7Combustion, engine8Combustion, engine1Power, engine2Power, engine3Power, engine4Power,
+ engine5Power, engine6Power, engine7Power, engine8Power) ==
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, rhs.engine7Combustion,
+ rhs.engine8Combustion, rhs.engine1Power, rhs.engine2Power, rhs.engine3Power, rhs.engine4Power,
+ rhs.engine5Power, rhs.engine6Power, rhs.engine7Power, rhs.engine8Power);
}
- void DataDefinitionRemoteAircraftPartsWithoutLights::setAllEngines(bool on)
+ void DataDefinitionRemoteAircraftPartsWithoutLights::setAllEngines(bool on, double power)
{
engine1Combustion = on ? 1 : 0;
engine2Combustion = on ? 1 : 0;
engine3Combustion = on ? 1 : 0;
engine4Combustion = on ? 1 : 0;
+ engine5Combustion = on ? 1 : 0;
+ engine6Combustion = on ? 1 : 0;
+ engine7Combustion = on ? 1 : 0;
+ engine8Combustion = on ? 1 : 0;
+ engine1Power = power;
+ engine2Power = power;
+ engine3Power = power;
+ engine4Power = power;
+ engine5Power = power;
+ engine6Power = power;
+ engine7Power = power;
+ engine8Power = power;
}
- void DataDefinitionRemoteAircraftPartsWithoutLights::setEngine(int number1based, bool on)
+ void DataDefinitionRemoteAircraftPartsWithoutLights::setEngine(int number1based, bool on, double power)
{
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;
+ case 1:
+ engine1Combustion = v;
+ engine1Power = power;
+ break;
+ case 2:
+ engine2Combustion = v;
+ engine2Power = power;
+ break;
+ case 3:
+ engine3Combustion = v;
+ engine3Power = power;
+ break;
+ case 4:
+ engine4Combustion = v;
+ engine4Power = power;
+ break;
+ case 5:
+ engine5Combustion = v;
+ engine5Power = power;
+ break;
+ case 6:
+ engine6Combustion = v;
+ engine6Power = power;
+ break;
+ case 7:
+ engine7Combustion = v;
+ engine7Power = power;
+ break;
+ case 8:
+ engine8Combustion = v;
+ engine8Power = power;
+ break;
default: break;
}
}
@@ -505,6 +589,18 @@ namespace swift::simplugin::fsxcommon
engine2Combustion = -1;
engine3Combustion = -1;
engine4Combustion = -1;
+ engine5Combustion = -1;
+ engine6Combustion = -1;
+ engine7Combustion = -1;
+ engine8Combustion = -1;
+ engine1Power = -1;
+ engine2Power = -1;
+ engine3Power = -1;
+ engine4Power = -1;
+ engine5Power = -1;
+ engine6Power = -1;
+ engine7Power = -1;
+ engine8Power = -1;
}
void DataDefinitionRemoteAircraftPartsWithoutLights::initFromParts(const CAircraftParts &parts)
@@ -517,10 +613,13 @@ namespace swift::simplugin::fsxcommon
flapsLeadingEdgeLeftPercent = lead;
flapsLeadingEdgeRightPercent = lead;
spoilersHandlePosition = parts.isSpoilersOut() ? 1.0 : 0.0;
- this->setAllEngines(false); // init
+ this->setAllEngines(false, 0.0); // init
int e = 1;
- for (const CAircraftEngine &engine : parts.getEngines()) { this->setEngine(e++, engine.isOn()); }
+ for (const CAircraftEngine &engine : parts.getEngines())
+ {
+ this->setEngine(e++, engine.isOn(), engine.getEnginePower());
+ }
}
CAircraftLights DataDefinitionRemoteAircraftLights::toLights() const
diff --git a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h
index d23a3497c..532ef9813 100644
--- a/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h
+++ b/src/plugins/simulator/fsxcommon/simconnectdatadefinition.h
@@ -69,16 +69,29 @@ namespace swift::simplugin::fsxcommon
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
+ double engine7Combustion; //!< Engine 7 combustion flag
+ double engine8Combustion; //!< Engine 8 combustion flag
+ // 42
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
+ // 48
double altitudeCalibratedFt; //!< Altitude without temperature effect (ft, FS2020)
- // 45
+ // 49
+ double engine1Power; //!< Engine 1 power
+ double engine2Power; //!< Engine 2 power
+ double engine3Power; //!< Engine 3 power
+ double engine4Power; //!< Engine 4 power
+ double engine5Power; //!< Engine 5 power
+ double engine6Power; //!< Engine 6 power
+ double engine7Power; //!< Engine 7 power
+ double engine8Power; //!< Engine 8 power
+ // 57
};
//! Data struct of aircraft position
@@ -148,6 +161,18 @@ namespace swift::simplugin::fsxcommon
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
+ double engine7Combustion; //!< Engine 7 combustion flag
+ double engine8Combustion; //!< Engine 8 combustion flag
+ double engine1Power; //!< Engine 1 power
+ double engine2Power; //!< Engine 2 power
+ double engine3Power; //!< Engine 3 power
+ double engine4Power; //!< Engine 4 power
+ double engine5Power; //!< Engine 5 power
+ double engine6Power; //!< Engine 6 power
+ double engine7Power; //!< Engine 7 power
+ double engine8Power; //!< Engine 8 power
//! Ctor
DataDefinitionRemoteAircraftPartsWithoutLights();
@@ -159,10 +184,10 @@ namespace swift::simplugin::fsxcommon
bool operator==(const DataDefinitionRemoteAircraftPartsWithoutLights &rhs) const;
//! All engines on/off
- void setAllEngines(bool on);
+ void setAllEngines(bool on, double power);
//! Set given engine
- void setEngine(int number1based, bool on);
+ void setEngine(int number1based, bool on, double power);
//! Reset all flaps
void resetAllFlaps();
@@ -262,7 +287,6 @@ namespace swift::simplugin::fsxcommon
ClientAreaSquawkBox
};
- // TODO TZ: are there any changes in MSFS2024
//! Handles SimConnect data definitions
class FSXCOMMON_EXPORT CSimConnectDefinitions
{
@@ -345,9 +369,6 @@ namespace swift::simplugin::fsxcommon
//! 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::fsxcommon
diff --git a/src/plugins/simulator/fsxcommon/simconnectsymbols.cpp b/src/plugins/simulator/fsxcommon/simconnectsymbols.cpp
index c2f12ef4b..3857f565d 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 f8fe6c997..01eb193a5 100644
--- a/src/plugins/simulator/fsxcommon/simconnectsymbols.h
+++ b/src/plugins/simulator/fsxcommon/simconnectsymbols.h
@@ -39,8 +39,6 @@ inline bool loadAndResolveP3DSimConnectByString(const QString &version)
FSXCOMMON_EXPORT bool loadAndResolveMSFSimConnect();
-FSXCOMMON_EXPORT bool loadAndResolveMSFS2024SimConnect();
-
#else
//! Load and resolve FSX SimConnect.
diff --git a/src/plugins/simulator/fsxcommon/simconnectwindows.h b/src/plugins/simulator/fsxcommon/simconnectwindows.h
index 541c1cc0f..fd402e0cb 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 e130562a6..d046b51cb 100644
--- a/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp
+++ b/src/plugins/simulator/fsxcommon/simulatorfsxcommon.cpp
@@ -437,9 +437,12 @@ namespace swift::simplugin::fsxcommon
this->sendRemoteAircraftPartsToSimulator(simObject, parts);
u++;
}
+
if (!situation.isNull())
{
SIMCONNECT_DATA_INITPOSITION position = this->aircraftSituationToFsxPosition(situation, true);
+ // set onground from parts, atherwise we could have a mismatch
+ position.OnGround = parts.isOnGround() ? 1 : 0;
const bool traceSendId = this->isTracingSendId();
const HRESULT hr = this->logAndTraceSendId(
SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSetPosition,
@@ -509,8 +512,7 @@ namespace swift::simplugin::fsxcommon
const CFsxP3DSettings settings = m_detailsSettings.getSettings(this->getSimulatorInfo());
m_useAddSimulatedObj = settings.isAddingAsSimulatedObjectEnabled();
m_useSbOffsets = settings.isSbOffsetsEnabled();
- if (this->getSimulatorPluginInfo().getSimulatorInfo().isMSFS() ||
- this->getSimulatorPluginInfo().getSimulatorInfo().isMSFS2024())
+ if (this->getSimulatorPluginInfo().getSimulatorInfo().isMSFS())
{
m_useSbOffsets = false; // Always disable SbOffsets for MSFS. Using new transponder mode property directly
}
@@ -528,7 +530,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())
{
@@ -746,7 +747,7 @@ namespace swift::simplugin::fsxcommon
for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index)
{
- engines.push_back(CAircraftEngine(index + 1, helperList.value(index, true)));
+ engines.push_back(CAircraftEngine(index + 1, helperList.value(index, true), 100));
}
const CAircraftParts parts(lights, dtb(simulatorOwnAircraft.gearHandlePosition),
@@ -2093,7 +2094,7 @@ namespace swift::simplugin::fsxcommon
void CSimulatorFsxCommon::updateRemoteAircraft()
{
- static_assert(sizeof(DataDefinitionRemoteAircraftPartsWithoutLights) == sizeof(double) * 10,
+ static_assert(sizeof(DataDefinitionRemoteAircraftPartsWithoutLights) == sizeof(double) * 22,
"DataDefinitionRemoteAircraftPartsWithoutLights has an incorrect size.");
Q_ASSERT_X(CThreadUtils::isInThisThread(this), Q_FUNC_INFO, "thread");
diff --git a/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp b/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp
index 68643c4aa..99fd79af8 100644
--- a/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp
+++ b/src/plugins/simulator/fsxcommon/simulatorfsxsimconnectproc.cpp
@@ -245,7 +245,7 @@ namespace swift::simplugin::fsxcommon
{
case CSimConnectDefinitions::RequestOwnAircraft:
{
- static_assert(sizeof(DataDefinitionOwnAircraft) == 45 * sizeof(double),
+ static_assert(sizeof(DataDefinitionOwnAircraft) == 57 * sizeof(double),
"DataDefinitionOwnAircraft has an incorrect size.");
const DataDefinitionOwnAircraft *ownAircaft =
reinterpret_cast(&pObjData->dwData);
diff --git a/src/plugins/simulator/msfs2024/CMakeLists.txt b/src/plugins/simulator/msfs2024/CMakeLists.txt
index d04f63955..2c82307a1 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 000000000..da7875508
--- /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 000000000..459958239
--- /dev/null
+++ b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.cpp
@@ -0,0 +1,665 @@
+// 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, "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,
+ "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,
+ "GENERAL ENG COMBUSTION:5", "Bool");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG COMBUSTION:6", "Bool");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG COMBUSTION:7", "Bool");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG COMBUSTION:8", "Bool");
+
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:1", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:2", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:3", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:4", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:5", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:6", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:7", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataOwnAircraft,
+ "GENERAL ENG THROTTLE LEVER POSITION:8", "percent");
+
+ 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::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG COMBUSTION:5", "Bool");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG COMBUSTION:6", "Bool");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG COMBUSTION:7", "Bool");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG COMBUSTION:8", "Bool");
+
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:1", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:2", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:3", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:4", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:5", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:6", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:7", "percent");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
+ "GENERAL ENG THROTTLE LEVER POSITION:8", "percent");
+
+ 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 RECOGNITION", "Bool");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights,
+ "LIGHT CABIN", "Bool");
+ hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftLights,
+ "LIGHT WING", "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_HELICOPTER);
+ hr += SimConnect_EnumerateSimObjectsAndLiveries(hSimConnect, CSimConnectDefinitions::REQUEST_HOT_AIR,
+ SIMCONNECT_SIMOBJECT_TYPE_HOT_AIR_BALLOON);
+
+ 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, engine5Combustion, engine6Combustion,
+ engine7Combustion, engine8Combustion, engine1Power, engine2Power, engine3Power, engine4Power,
+ engine5Power, engine6Power, engine7Power, engine8Power) ==
+ std::tie(rhs.flapsLeadingEdgeLeftPercent, rhs.flapsLeadingEdgeRightPercent,
+ rhs.flapsTrailingEdgeLeftPercent, rhs.flapsTrailingEdgeRightPercent, rhs.gearHandlePosition,
+ rhs.spoilersHandlePosition, rhs.engine1Combustion, rhs.engine2Combustion, rhs.engine3Combustion,
+ rhs.engine4Combustion, rhs.engine5Combustion, rhs.engine6Combustion, rhs.engine7Combustion,
+ rhs.engine8Combustion, rhs.engine1Power, rhs.engine2Power, rhs.engine3Power, rhs.engine4Power,
+ rhs.engine5Power, rhs.engine6Power, rhs.engine7Power, rhs.engine8Power);
+ }
+
+ void DataDefinitionRemoteAircraftPartsWithoutLights::setAllEngines(bool on, double power)
+ {
+ engine1Combustion = on ? 1 : 0;
+ engine2Combustion = on ? 1 : 0;
+ engine3Combustion = on ? 1 : 0;
+ engine4Combustion = on ? 1 : 0;
+ engine5Combustion = on ? 1 : 0;
+ engine6Combustion = on ? 1 : 0;
+ engine7Combustion = on ? 1 : 0;
+ engine8Combustion = on ? 1 : 0;
+ engine1Power = power;
+ engine2Power = power;
+ engine3Power = power;
+ engine4Power = power;
+ engine5Power = power;
+ engine6Power = power;
+ engine7Power = power;
+ engine8Power = power;
+ }
+
+ void DataDefinitionRemoteAircraftPartsWithoutLights::setEngine(int number1based, bool on, double power)
+ {
+ double v = on ? 1.0 : 0.0;
+ switch (number1based)
+ {
+ case 1:
+ engine1Combustion = v;
+ engine1Power = power;
+ break;
+ case 2:
+ engine2Combustion = v;
+ engine2Power = power;
+ break;
+ case 3:
+ engine3Combustion = v;
+ engine3Power = power;
+ break;
+ case 4:
+ engine4Combustion = v;
+ engine4Power = power;
+ break;
+ case 5:
+ engine5Combustion = v;
+ engine5Power = power;
+ break;
+ case 6:
+ engine6Combustion = v;
+ engine6Power = power;
+ break;
+ case 7:
+ engine7Combustion = v;
+ engine7Power = power;
+ break;
+ case 8:
+ engine8Combustion = v;
+ engine8Power = power;
+ 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;
+ engine5Combustion = -1;
+ engine6Combustion = -1;
+ engine7Combustion = -1;
+ engine8Combustion = -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, 0.0); // init
+
+ int e = 1;
+ for (const CAircraftEngine &engine : parts.getEngines())
+ {
+ this->setEngine(e++, engine.isOn(), engine.getEnginePower());
+ }
+ }
+
+ CAircraftLights DataDefinitionRemoteAircraftLights::toLights() const
+ {
+ return CAircraftLights(dtb(lightStrobe), dtb(lightLanding), dtb(lightTaxi), dtb(lightBeacon), dtb(lightNav),
+ dtb(lightLogo), dtb(lightRecognition), dtb(lightCabin), dtb(lightWing));
+ }
+
+ 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 000000000..0b04fd175
--- /dev/null
+++ b/src/plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h
@@ -0,0 +1,413 @@
+// 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?
+ 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
+ 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
+ // 33
+ double flapsHandlePosition; //!< Flaps handle position in percent
+ double spoilersHandlePosition; //!< Spoilers out? (flag)
+ double gearHandlePosition; //!< Gear handle position (flag)
+ // 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
+ double engine5Combustion; //!< Engine 5 combustion flag
+ double engine6Combustion; //!< Engine 6 combustion flag
+ double engine7Combustion; //!< Engine 7 combustion flag
+ double engine8Combustion; //!< Engine 8 combustion flag
+ // 46
+ 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
+ // 52
+ double altitudeCalibratedFt; //!< Altitude without temperature effect (ft, FS2020)
+ // 53
+ double engine1Power; //!< Engine 1 power
+ double engine2Power; //!< Engine 2 power
+ double engine3Power; //!< Engine 3 power
+ double engine4Power; //!< Engine 4 power
+ double engine5Power; //!< Engine 5 power
+ double engine6Power; //!< Engine 6 power
+ double engine7Power; //!< Engine 7 power
+ double engine8Power; //!< Engine 8 power
+ // 61
+ };
+
+ //! Data struct of aircraft position
+ struct DataDefinitionOwnAircraftModel
+ {
+ char title[256]; //!< Aircraft model string
+ char livery[256]; //!< Aircraft livery string msfs2024
+ };
+
+ //! 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
+ char livery[256]; //!< Aircraft livery string msfs2024
+ };
+
+ //! 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
+ double engine5Combustion; //!< Engine 5 combustion flag
+ double engine6Combustion; //!< Engine 6 combustion flag
+ double engine7Combustion; //!< Engine 7 combustion flag
+ double engine8Combustion; //!< Engine 8 combustion flag
+ double engine1Power; //!< Engine 1 power
+ double engine2Power; //!< Engine 2 power
+ double engine3Power; //!< Engine 3 power
+ double engine4Power; //!< Engine 4 power
+ double engine5Power; //!< Engine 5 power
+ double engine6Power; //!< Engine 6 power
+ double engine7Power; //!< Engine 7 power
+ double engine8Power; //!< Engine 8 power
+
+ //! 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, double power);
+
+ //! Set given engine
+ void setEngine(int number1based, bool on, double power);
+
+ //! 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
+ double lightWing; //!< 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,
+ RequestSimEnvironment,
+ 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 000000000..fd05e0800
--- /dev/null
+++ b/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.cpp
@@ -0,0 +1,516 @@
+// 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
+
+#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 = 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 = 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 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::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 u("unknown");
+ switch (type)
+ {
+ case AircraftNonAtc: return a1;
+ case AircraftSimulatedObject: return a2;
+ 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();
+ }
+
+ // TODO TZ optimize?
+ 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;
+ }
+
+ // TODO TZ optimize?
+ 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;
+ }
+
+ bool CSimConnectObjects::containsPendingAdded() const
+ {
+ bool cont = false;
+ for (const CSimConnectObject &simObject : *this)
+ {
+ if (simObject.isPendingAdded())
+ {
+
+ CLogMessage(this).info(u"containsPendingAdded %1 ") << simObject.getCallsign();
+ cont = true;
+ }
+ }
+ if (cont) 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;
+ }
+
+ 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 000000000..b94048c25
--- /dev/null
+++ b/src/plugins/simulator/msfs2024/simconnectobjectmsfs2024.h
@@ -0,0 +1,440 @@
+// 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,
+ 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; }
+
+ //! 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 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;
+
+ //! 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 000000000..68aaadfe0
--- /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 SimConnectSymbolsMsfs2024
+{
+ 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 SimConnectSymbolsMsfs2024 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 000000000..805701ff7
--- /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 000000000..b5c84a94c
--- /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 818a2d7ae..10ff7061c 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,14 +13,14 @@ 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({ "A320NEO V2", CAircraftModel::TypeModelMatchingDefaultModel,
"Airbus A320 default model", CAircraftIcaoCode("A320", "L2J") });
@@ -29,7 +29,7 @@ namespace swift::simplugin::msfs2024
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 2ca045eee..579d04a41 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 000000000..9480a1eb1
--- /dev/null
+++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.cpp
@@ -0,0 +1,3101 @@
+// 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/context/contextsimulator.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/interpolation/interpolatormulti.h"
+#include "misc/simulation/msfs2024/simconnectutilities.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::core::context;
+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::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);
+ }
+
+ 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");
+
+ 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;
+ }
+
+ if (sSimmobjectLoadedState.bAirplaneLoaded && sSimmobjectLoadedState.bHelicopterLoaded &&
+ sSimmobjectLoadedState.bHotAirLoaded)
+ {
+ 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()
+ {
+ CLogMessage(this).info(u"%1 SimObjects and Liveries in vSimObjectsAndLiveries")
+ << vSimObjectsAndLiveries.size();
+
+ auto *worker = CWorker::fromTask(this, "createNewModelList", [=]() {
+ this->createNewModelList();
+ return QVariant(); // void-Result
+ });
+
+ // 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"); });
+ }
+
+ void CSimulatorMsfs2024::createNewModelList()
+ {
+
+ 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)
+ {
+ const sSimObjectLivery &modelLivery = vSimObjectsAndLiveries[i];
+
+ CAircraftModel model;
+ 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
+
+ // we need the combined string of the model for further processing
+ 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;
+ 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
+
+ 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);
+ }
+
+ 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 = false;
+ bool sortByDistributor = true;
+ bool consolidateWithDb = false;
+ bool ShowAllInstalledModels = true; // msfs20424 always show all installed models
+
+ if (gui_application)
+ {
+ givenDistributorsOnly = m_generic.getPropertyDistributorFiltered();
+ dbDataOnly = m_generic.getPropertyWithDbEntry();
+ incremnental = false;
+ consolidateWithDb = true;
+ ShowAllInstalledModels = true;
+ }
+
+ // CDistributorList distributorList;
+ // for (const QString &name : distributorNames) { distributorList.push_back(CDistributor(name)); }
+ CDistributorList distributorList = sGui->getWebDataServices()->getDistributors();
+
+ CModelSetBuilder builder(nullptr);
+ 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 (ShowAllInstalledModels) { options |= CModelSetBuilder::ShowAllInstalledModels; }
+ const CSimulatorInfo &simulator = this->getSimulatorInfo();
+
+ CCentralMultiSimulatorModelSetCachesProvider::modelCachesInstance().synchronizeCache(simulator);
+ currentSet = CCentralMultiSimulatorModelSetCachesProvider::modelCachesInstance().getCachedModels(simulator);
+
+ NewSet = builder.buildModelSet(simulator, newModelList, currentSet, options, distributorList);
+ NewSet.setSimulatorInfo(simulator);
+
+ // for swiftgui it is enough to set the cache here
+ if (gui_application)
+ CCentralMultiSimulatorModelSetCachesProvider::modelCachesInstance().setModelsForSimulator(NewSet,
+ simulator);
+ CCentralMultiSimulatorModelCachesProvider::modelCachesInstance().setCachedModels(NewSet, simulator);
+
+ sGui->getIContextSimulator()->setModelSetLoaderSimulator(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 can used 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)
+ {
+ Q_UNUSED(situation);
+ 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->aircraftSituationToPosition(situation, true);
+ // set onground from parts, atherwise we could have a mismatch
+ position.OnGround = parts.isOnGround() ? 1 : 0;
+ 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; }
+ 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::RequestSimEnvironment,
+ CSimConnectDefinitions::DataSimEnvironment, SIMCONNECT_OBJECT_ID_USER,
+ SIMCONNECT_PERIOD_SECOND, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED),
+ "Cannot request sim.env.", Q_FUNC_INFO, "SimConnect_RequestDataOnSimObject");
+
+ hr += this->logAndTraceSendId(SimConnect_RequestDataOnSimObject(
+ m_hSimConnect, CSimConnectDefinitions::RequestMSFSTransponder,
+ CSimConnectDefinitions::DataTransponderModeMSFS, SIMCONNECT_OBJECT_ID_USER,
+ 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;
+ }
+
+ 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);
+ }
+
+ 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 MSFS2024 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"MSFS2024: Pitch value (own aircraft) out of limits: %1")
+ << simulatorOwnAircraft.pitchDeg;
+ }
+ CAircraftSituation aircraftSituation;
+ aircraftSituation.setMSecsSinceEpoch(ts);
+ aircraftSituation.setPosition(position);
+ // 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()));
+ 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),
+ 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),
+ dtb(simulatorOwnAircraft.engine5Combustion), dtb(simulatorOwnAircraft.engine6Combustion),
+ dtb(simulatorOwnAircraft.engine7Combustion), dtb(simulatorOwnAircraft.engine8Combustion)
+ };
+
+ for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index)
+ {
+ engines.push_back(CAircraftEngine(index + 1, helperList.value(index, true), 100));
+ }
+
+ 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; }
+
+ // TODO TZ check this entire function for msfs2024
+ // slower updates
+ if (m_ownAircraftUpdateCycles % 10 == 0)
+ {
+ // 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);
+ });
+ }
+
+ // called decoupled from simconnect event queue very fast
+ 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);
+ }
+ }
+ }
+
+ // called decoupled from simconnect event queue
+ 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; }
+
+ 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);
+
+ // 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::updateMSFS2024TransponderMode(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());
+
+ CLogMessage(this).info(u"simulatorReportedObjectAdded 1 %1 %2 %3")
+ << callsign.asString() << objectId << this->isSimulating();
+
+ if (!simObject.hasValidRequestAndObjectId() || callsign.isEmpty())
+ {
+ CLogMessage(this).error(u"simulatorReportedObjectAdded 1 %1 %2 %3")
+ << callsign.asString() << objectId << this->isSimulating();
+
+ 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, [=] {
+ 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; }
+
+ CLogMessage(this).info(u"verifyAddedRemoteAircraft 1 %1") << remoteAircraftIn.getCallsign();
+
+ 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?
+ const bool verifiedAircraft = true;
+ // 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::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());
+ CCallsignSet toBeRemovedCallsigns;
+
+ // TODO TZ this removed the pending aircraft from the list, even they are not added yet
+ // for (const CSimConnectObject &pendingSimObj : std::as_const(m_addPendingAircraft))
+ //{
+ // SWIFT_VERIFY_X(pendingSimObj.hasCallsign(), Q_FUNC_INFO, "missing callsign");
+ // if (!pendingSimObj.hasCallsign()) { continue; }
+ // else { toBeRemovedCallsigns.push_back(pendingSimObj.getCallsign()); }
+ //}
+
+ // no longer required to be added
+ // TOTO TZ
+ m_addPendingAircraft.removeCallsigns(toBeRemovedCallsigns);
+ m_addAgainAircraftWhenRemoved.removeByCallsigns(toBeRemovedCallsigns);
+
+ // add aircraft, but "non blocking"
+ if (!m_addPendingAircraft.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; }
+ 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);
+ }
+ // TODO TZ check if required
+ CLogMessage(this).info(u"removeFromAddPendingAndAddAgainAircraft 3 %1 m_addPendingAircraft.count: %2")
+ << simObjectOld.getCallsignAsString() << m_addPendingAircraft.count();
+
+ 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" });
+ }
+
+ 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());
+
+ // 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() && true)
+ {
+ 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();
+ m_addPendingAircraft.insert(addPendingObj, true); // insert removed objects and update ts
+ 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))
+ if (!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();
+
+ bool adding = false; // will be added flag
+ const SIMCONNECT_DATA_REQUEST_ID requestId = 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::aircraftSituationToPosition(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).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 (this->isAddingAsSimulatedObjectEnabled() && correspondingSimObject.hasCallsign() &&
+ correspondingSimObject.getAddingExceptions() > 0 &&
+ correspondingSimObject.getType() == CSimConnectObject::AircraftNonAtc)
+ {
+ CStatusMessage(this).warning(
+ u"Model '%1' for '%2' failed %3 time(s) before, using SimConnect_AICreateSimulatedObject_EX1 now")
+ << newRemoteAircraft.getModelString() << callsign.toQString()
+ << correspondingSimObject.getAddingExceptions();
+
+ hr = SimConnect_AICreateSimulatedObject_EX1(m_hSimConnect, modelStringBa.constData(),
+ modelLiveryBa.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::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; }
+
+ // 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"MSFS2024 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, 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"MSFS2024 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"MSFS2024 plugin: initEvents failed");
+ return hr;
+ }
+
+ // init data definitions and SB data area
+ hr += this->initDataDefinitionsWhenConnected();
+ if (isFailure(hr))
+ {
+ CLogMessage(this).error(u"MSFS2024 plugin: initDataDefinitionsWhenConnected failed");
+ return hr;
+ }
+
+ return hr;
+ }
+
+ void CSimulatorMsfs2024::updateRemoteAircraft()
+ {
+ static_assert(sizeof(DataDefinitionRemoteAircraftPartsWithoutLights) == sizeof(double) * 22,
+ "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->aircraftSituationToPosition(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;
+ }
+
+ 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");
+
+ // TODO TZ handle flaps more precisely
+ // is already handled in parts definition above
+ // 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 = S_OK;
+ // 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");
+
+ 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 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");
+
+ 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 & hr5 & hr6 & hr7 & hr8 & hr9 & hr10 & hr11 & hr12));
+ }
+
+ bool CSimulatorMsfs2024::sendRemoteAircraftAtcDataToSimulator(const CSimConnectObject &simObject)
+ {
+ if (!simObject.isReadyToSend()) { 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);
+ }
+
+ SIMCONNECT_DATA_INITPOSITION
+ 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");
+
+ // 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 MSFS2024 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::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_sendIdTraces.clear();
+ }
+
+ void CSimulatorMsfs2024::clearAllRemoteAircraftData()
+ {
+ // m_addAgainAircraftWhenRemoved cleared below
+ CSimulatorFsCommon::clearAllRemoteAircraftData(); // also removes aircraft
+ m_simConnectObjects.clear();
+ m_addPendingAircraft.clear();
+ m_simConnectObjectsPositionAndPartsTraces.clear();
+ }
+
+ 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);
+ }
+
+ 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;
+ }
+
+ 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::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.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 000000000..d6c5b52fe
--- /dev/null
+++ b/src/plugins/simulator/msfs2024/simulatormsfs2024common.h
@@ -0,0 +1,762 @@
+// SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
+// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
+
+//! \file
+
+#ifndef SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMULATORMSFS2024COMMON_H
+#define SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMULATORMSFS2024COMMON_H
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "config/buildconfig.h"
+#include "core/simulator.h"
+#include "gui/components/dbmappingcomponentaware.h"
+#include "misc/aviation/airportlist.h"
+#include "misc/aviation/altitude.h"
+#include "misc/datacache.h"
+#include "misc/network/client.h"
+#include "misc/pixmap.h"
+#include "misc/pq/frequency.h"
+#include "misc/simulation/aircraftmodel.h"
+#include "misc/simulation/data/modelcaches.h" // TODO ???
+#include "misc/simulation/interpolation/interpolatorlinear.h"
+#include "misc/simulation/settings/modelmatchersettings.h"
+#include "misc/simulation/settings/simulatorsettings.h"
+#include "misc/simulation/simulatedaircraft.h"
+#include "misc/simulation/simulatorplugininfo.h"
+#include "misc/statusmessage.h"
+#include "plugins/simulator/fscommon/simulatorfscommon.h"
+#include "plugins/simulator/msfs2024/msfs2024export.h"
+#include "plugins/simulator/msfs2024/simconnectdatadefinitionmsfs2024.h"
+#include "plugins/simulator/msfs2024/simconnectobjectmsfs2024.h"
+#include "plugins/simulator/msfs2024/simconnectsymbolsmsfs2024.h"
+#include "plugins/simulator/msfs2024/simconnectwindowsmsfs2024.h"
+
+namespace swift::simplugin::msfs2024common
+{
+ //! SimConnect Event IDs
+ enum EventIds
+ {
+ SystemEventSimStatus,
+ SystemEventObjectAdded,
+ SystemEventObjectRemoved,
+ SystemEventSlewToggle,
+ SystemEventFrame,
+ SystemEventPause,
+ SystemEventFlightLoaded,
+ EventPauseToggle,
+ EventFreezeLatLng,
+ EventFreezeAlt,
+ EventFreezeAtt,
+ EventSetCom1Active,
+ EventSetCom2Active,
+ EventSetCom1Standby,
+ EventSetCom2Standby,
+ EventSetTransponderCode,
+ EventTextMessage,
+ EventSetTimeZuluYear,
+ EventSetTimeZuluDay,
+ EventSetTimeZuluHours,
+ EventSetTimeZuluMinutes,
+ // ------------ lights -------------
+ // EventLandingLightsOff,
+ // EventLandinglightsOn,
+ EventLandingLightsSet,
+ // EventLandingLightsToggle,
+ // EventPanelLightsOff,
+ // EventPanelLightsOn,
+ EventPanelLightsSet,
+ // EventStrobesOff,
+ // EventStrobesOn,
+ EventStrobesSet,
+ // EventStrobesToggle,
+ EventBeaconLightsSet,
+ EventCabinLightsSet,
+ EventLogoLightsSet,
+ EventNavLightsSet,
+ EventRecognitionLightsSet,
+ EventTaxiLightsSet,
+ EventWingLightsSet,
+ // ------------- flaps -------------
+ EventFlapsSet,
+ EventGearSet,
+ // ---------- end marker -----------
+ EventFSXEndMarker
+ };
+
+ //! Struct to trace send ids
+ struct TraceFsxSendId
+ {
+ //! Ctor
+ TraceFsxSendId(DWORD sendId, const CSimConnectObject &simObject, const QString &comment)
+ : sendId(sendId), simObject(simObject), comment(comment)
+ {}
+
+ // DWORD is unsigned
+ DWORD sendId = 0; //!< the send id
+ CSimConnectObject simObject; //!< CSimConnectObject at the time of the trace
+ QString comment; //!< where sent
+
+ //! For aircraft
+ bool isForAircraft() const { return simObject.getType() == CSimConnectObject::AircraftNonAtc; }
+
+ //! Invalid trace?
+ bool isInvalid() const { return sendId == 0 && simObject.isInvalid() == 0 && comment.isEmpty(); }
+
+ //! Valid trace?
+ bool isValid() const { return !this->isInvalid(); }
+
+ //! Invalid object
+ static const TraceFsxSendId &invalid()
+ {
+ static const TraceFsxSendId i(0, CSimConnectObject(), "");
+ return i;
+ }
+ };
+
+ //! Buffer for models read from SimConnect
+ struct sSimObjectLivery
+ {
+ QString szSimObjectCombinedTitle;
+ QString szSimObjectTitle;
+ QString szLiveryName;
+ };
+
+ //! Flags for the load status of reading from the SimConnect
+ struct sSimmobjectLoaded
+ {
+ bool bLoadStarted = false;
+ bool bAirplaneLoaded = false;
+ bool bHelicopterLoaded = false;
+ bool bHotAirLoaded = false;
+ };
+
+ //! FSX Simulator Implementation
+ class MSFS2024_EXPORT CSimulatorMsfs2024 : public fscommon::CSimulatorFsCommon
+ {
+ Q_OBJECT
+ Q_INTERFACES(swift::core::ISimulator)
+ Q_INTERFACES(swift::misc::simulation::ISimulationEnvironmentProvider)
+ Q_INTERFACES(swift::misc::simulation::IInterpolationSetupProvider)
+
+ public:
+ //! Constructor, parameters as in \sa swift::core::ISimulatorFactory::create
+ CSimulatorMsfs2024(const swift::misc::simulation::CSimulatorPluginInfo &info,
+ swift::misc::simulation::IOwnAircraftProvider *ownAircraftProvider,
+ swift::misc::simulation::IRemoteAircraftProvider *remoteAircraftProvider,
+ swift::misc::network::IClientProvider *clientProvider, QObject *parent = nullptr);
+
+ //! Destructor
+ virtual ~CSimulatorMsfs2024() override;
+
+ //! \name ISimulator implementations
+ //! @{
+ virtual bool connectTo() override;
+ virtual bool disconnectFrom() override;
+ virtual bool
+ physicallyAddRemoteAircraft(const swift::misc::simulation::CSimulatedAircraft &newRemoteAircraft) override;
+ virtual bool physicallyRemoveRemoteAircraft(const swift::misc::aviation::CCallsign &callsign) override;
+ virtual int physicallyRemoveAllRemoteAircraft() override;
+ virtual bool updateOwnSimulatorCockpit(const swift::misc::simulation::CSimulatedAircraft &ownAircraft,
+ const swift::misc::CIdentifier &originator) override;
+ virtual bool updateOwnSimulatorSelcal(const swift::misc::aviation::CSelcal &selcal,
+ const swift::misc::CIdentifier &originator) override;
+ virtual void displayStatusMessage(const swift::misc::CStatusMessage &message) const override;
+ virtual void displayTextMessage(const swift::misc::network::CTextMessage &message) const override;
+ virtual bool isPhysicallyRenderedAircraft(const swift::misc::aviation::CCallsign &callsign) const override;
+ virtual swift::misc::aviation::CCallsignSet physicallyRenderedAircraft() const override;
+ virtual swift::misc::CStatusMessageList debugVerifyStateAfterAllAircraftRemoved() const override;
+ virtual QString getStatisticsSimulatorSpecific() const override;
+ virtual void resetAircraftStatistics() override;
+ virtual void setFlightNetworkConnected(bool connected) override;
+ virtual swift::misc::CStatusMessageList
+ getInterpolationMessages(const swift::misc::aviation::CCallsign &callsign) const override;
+ virtual bool testSendSituationAndParts(const swift::misc::aviation::CCallsign &callsign,
+ const swift::misc::aviation::CAircraftSituation &situation,
+ const swift::misc::aviation::CAircraftParts &parts) override;
+ //! @}
+
+ ////! \copydoc swift::misc::simulation::ISimulationEnvironmentProvider::requestElevation
+ ////! \remark x86 FSX version, x64 version is overridden
+ ////! \sa CSimulatorFsxCommon::is
+ // virtual bool requestElevation(const swift::misc::geo::ICoordinateGeodetic &reference,
+ // const swift::misc::aviation::CCallsign &aircraftCallsign) override;
+
+ //! saves the SimObjects received from the simulator a structure
+ void CacheSimObjectAndLiveries(const SIMCONNECT_RECV_ENUMERATE_SIMOBJECT_AND_LIVERY_LIST *msg);
+
+ //! Write the sim objects and liveries to file and give back the number of objects written
+ int writeSimObjectsAndLiveriesToFile(const swift::misc::simulation::CAircraftModelList Modelset);
+
+ //! creates a new model list
+ void createNewModelList();
+
+ //! resets the sim object and liveries cache
+ void setSimObjectAndLiveries();
+
+ //! Tracing right now?
+ bool isTracingSendId() const;
+
+ //! Trace enable (can be auto enable also)
+ bool isTraceSendId() const { return m_traceSendId; }
+
+ //! Set tracing on/off
+ void setTractingSendId(bool trace);
+
+ //! Using the SB offsets?
+ bool isUsingSbOffsetValues() const { return m_useSbOffsets; }
+
+ //! Use SB offset values
+ void setUsingSbOffsetValues(bool use);
+
+ //! Number of received SB4 packets
+ //! \remark if this is increasing, SB4 is supported
+ int receivedSBPackets() const { return m_sbDataReceived; }
+
+ //! Allow adding as simulated object instead of non ATC
+ bool isAddingAsSimulatedObjectEnabled() const { return m_useAddSimulatedObj; }
+
+ //! Allow adding as simulated object instead of non ATC
+ void setAddingAsSimulatedObjectEnabled(bool enabled);
+
+ //! Request for sim data (request in range of sim data)?
+ static bool isRequestForSimObjAircraft(DWORD requestId)
+ {
+ return requestId >= RequestSimObjAircraftStart && requestId <= RequestSimObjAircraftRangeEnd;
+ }
+
+ //! Request for any CSimConnectObject?
+ static bool isRequestForSimConnectObject(DWORD requestId) { return isRequestForSimObjAircraft(requestId); }
+
+ //! Sub request type
+ static CSimConnectDefinitions::SimObjectRequest requestToSimObjectRequest(DWORD requestId);
+
+ //! Random unit text request id
+ //! \private
+ static DWORD unitTestRequestId(CSimConnectObject::SimObjectType type);
+
+ //! Encapsulates creating QString from FSX string data
+ static QString fsxCharToQString(const char *fsxChar, int size = -1);
+
+ protected:
+ //! SimConnect callback
+ //! \note all tasks called in this function (i.e, all called functions) must perform fast or shall be called
+ //! asynchronously
+ static void CALLBACK SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext);
+
+ //! \name Interface implementations
+ //! @{
+ virtual bool isConnected() const override;
+ virtual bool isSimulating() const override;
+ //! @}
+
+ //! \name Base class overrides
+ //! @{
+ virtual void reset() override;
+ virtual void initSimulatorInternals() override;
+ virtual void clearAllRemoteAircraftData() override;
+ virtual void onOwnModelChanged(const swift::misc::simulation::CAircraftModel &newModel) override;
+ //! @}
+
+ //! Timer event (our SimConnect event loop), runs dispatch
+ //! \sa m_timerId
+ //! \sa CSimulatorFsxCommon::dispatch
+ virtual void timerEvent(QTimerEvent *event) override;
+
+ //! Specific P3D events
+ virtual HRESULT initEventsP3D();
+
+ //! \ingroup swiftdotcommands
+ //!
+ //! .drv sendid on|off tracing simConnect sendId on/off
+ //!
+ virtual bool parseDetails(const swift::misc::CSimpleCommandParser &parser) override;
+
+ //! Trigger tracing ids for some while
+ //! \sa CSimulatorFsxCommon::isTracingSendId
+ bool triggerAutoTraceSendId(qint64 traceTimeMs = AutoTraceOffsetMs);
+
+ //! Callsign for pending request
+ swift::misc::aviation::CCallsign getCallsignForPendingProbeRequests(DWORD requestId, bool remove);
+
+ //! Get new request id, overflow safe
+ SIMCONNECT_DATA_REQUEST_ID obtainRequestIdForSimObjAircraft();
+
+ //! Release AI control
+ //! \remark P3D version is overridden
+ virtual bool releaseAIControl(const CSimConnectObject &simObject, SIMCONNECT_DATA_REQUEST_ID requestId);
+
+ //! Valid CSimConnectObject which is NOT pendig removed
+ bool isValidSimObjectNotPendingRemoved(const CSimConnectObject &simObject) const;
+
+ //! CSimConnectObject for trace
+ CSimConnectObject getSimObjectForTrace(const TraceFsxSendId &trace) const;
+
+ //! Remove the CSimConnectObject linked in the trace
+ bool removeSimObjectForTrace(const TraceFsxSendId &trace);
+
+ //! Remove camera if any
+ // virtual void removeCamera(CSimConnectObject &simObject);
+
+ //! Remove observer if any
+ // virtual void removeObserver(CSimConnectObject &simObject);
+
+ //! Trace if required, log errors
+ HRESULT logAndTraceSendId(HRESULT hr, const QString &warningMsg, const QString &functionName,
+ const QString &functionDetails = {});
+
+ //! Trace if required, log errors
+ HRESULT logAndTraceSendId(HRESULT hr, const CSimConnectObject &simObject, const QString &warningMsg,
+ const QString &functionName, const QString &functionDetails = {});
+
+ //! Trace if required, log errors
+ HRESULT logAndTraceSendId(HRESULT hr, bool traceSendId, const CSimConnectObject &simObject,
+ const QString &warningMsg, const QString &functionName,
+ const QString &functionDetails = {});
+
+ //! Convert to FSX char array
+ static QByteArray toFsxChar(const QString &string);
+
+ //! Register help
+ static void registerHelp();
+
+ //! @{
+ //! Word size
+ static bool is32bit() { return (swift::config::CBuildConfig::buildWordSize() == 32); }
+ static bool is64bit() { return (swift::config::CBuildConfig::buildWordSize() == 64); }
+ //! @}
+
+ //! Format conversion
+ //! \note must be valid situation
+ static SIMCONNECT_DATA_INITPOSITION
+ aircraftSituationToPosition(const swift::misc::aviation::CAircraftSituation &situation, bool sendGnd = true,
+ bool forceUnderflowDetection = false,
+ swift::misc::CStatusMessage *details = nullptr);
+
+ //! Format conversion
+ //! \note must be valid situation
+ static SIMCONNECT_DATA_PBH
+ aircraftSituationToFsxPBH(const swift::misc::aviation::CAircraftSituation &situation);
+
+ //! Format conversion
+ static SIMCONNECT_DATA_INITPOSITION
+ coordinateToFsxPosition(const swift::misc::geo::ICoordinateGeodetic &coordinate);
+
+ //! Format conversion
+ static SIMCONNECT_DATA_LATLONALT
+ coordinateToFsxLatLonAlt(const swift::misc::geo::ICoordinateGeodetic &coordinate);
+
+ //! Valid FSX/P3D position
+ static bool isValidFsxPosition(const SIMCONNECT_DATA_INITPOSITION &fsxPos);
+
+ //! Valid 180degrees value
+ static bool isValid180Deg(double deg) { return deg > -180.0 && deg <= 180.0; }
+
+ static constexpr qint64 AutoTraceOffsetMs = 10 * 1000; //!< how long do we trace?
+ HANDLE m_hSimConnect = nullptr; //!< handle to SimConnect object
+ DispatchProc m_dispatchProc = &CSimulatorMsfs2024::SimConnectProc; //!< called function for dispatch, can be
+ //!< overriden by specialized P3D function
+ CSimConnectObjects m_simConnectObjects; //!< AI objects and their object and request ids
+
+ QMap
+ m_pendingProbeRequests; //!< pending elevation requests: requestId/aircraft callsign
+
+ swift::misc::physical_quantities::CLength m_altitudeDelta; //!< FS2020 effect of temperature on altitude
+
+ private:
+ //! Reason for adding an aircraft
+ enum AircraftAddMode
+ {
+ ExternalCall, //!< normal external request to add aircraft
+ AddByTimer, //!< add pending aircraft by timer
+ AddAfterAdded, //!< add pending because object successfully added
+ AddedAfterRemoved //!< added again after removed
+ };
+
+ //! Mode as string
+ static const QString &modeToString(AircraftAddMode mode);
+
+ //! Dispatch SimConnect messages
+ //! \remark very frequently called
+ void dispatch();
+
+ //! Implementation of add remote aircraft, which also handles FSX specific adding one by one
+ //! \remark main purpose of this function is to only add one aircraft at a time, and only if simulator is not
+ //! paused/stopped
+ bool physicallyAddRemoteAircraftImpl(const swift::misc::simulation::CSimulatedAircraft &newRemoteAircraft,
+ AircraftAddMode addMode,
+ const CSimConnectObject &correspondingSimObject = {});
+
+ //! Remove aircraft no longer in provider
+ //! \remark kind of cleanup function, in an ideal scenario this should never need to cleanup something
+ swift::misc::aviation::CCallsignSet physicallyRemoveAircraftNotInProvider();
+
+ //! ASynchronous version of physicallyRemoveAircraftNotInProvider
+ void physicallyRemoveAircraftNotInProviderAsync();
+
+ //! Verify that an object has been added in simulator
+ //! \remark checks if the object was really added after an "add request" and not directly removed again
+ //! \remark requests further data on remote aircraft (lights, ..) when correctly added
+ void verifyAddedRemoteAircraft(const swift::misc::simulation::CSimulatedAircraft &remoteAircraftIn);
+
+ //! Adding an aircraft failed
+ void addingAircraftFailed(const CSimConnectObject &simObject);
+
+ //! Create a detailed info about the failed aircraft
+ bool verifyFailedAircraftInfo(const CSimConnectObject &simObject, swift::misc::CStatusMessage &details) const;
+
+ //! Logging version of verifyFailedAircraftInfo
+ bool logVerifyFailedAircraftInfo(const CSimConnectObject &simObject) const;
+
+ //! Add next aircraft based on timer
+ void timerBasedObjectAddOrRemove();
+
+ //! Add next aircraft after another has been confirmed
+ void addPendingAircraftAfterAdded();
+
+ //! Try to add the next aircraft (one by one)
+ void addPendingAircraft(AircraftAddMode mode);
+
+ //! Remove as m_addPendingAircraft and m_aircraftToAddAgainWhenRemoved
+ CSimConnectObject removeFromAddPendingAndAddAgainAircraft(const swift::misc::aviation::CCallsign &callsign);
+
+ //! Call this method to declare the simulator connected
+ void setSimConnected();
+
+ //! Called when simulator has started
+ void onSimRunning();
+
+ //! Deferred version of onSimRunning to avoid jitter
+ void onSimRunningDeferred(qint64 referenceTs);
+
+ //! Called every visual frame
+ void onSimFrame();
+
+ //! Called when simulator has stopped, e.g. by selecting the "select aircraft screen"
+ void onSimStopped();
+
+ //! Simulator is going down
+ void onSimExit();
+
+ //! Init when connected
+ HRESULT initWhenConnected();
+
+ //! Initialize SimConnect system events
+ HRESULT initEvents();
+
+ //! Initialize SimConnect data definitions
+ HRESULT initDataDefinitionsWhenConnected();
+
+ //! Update remote aircraft
+ //! \remark this is where the interpolated data are sent
+ void updateRemoteAircraft();
+
+ //! Update remote aircraft parts (send to FSX)
+ bool updateRemoteAircraftParts(const CSimConnectObject &simObject,
+ const swift::misc::simulation::CInterpolationResult &result, bool forcedUpdate);
+
+ //! Send parts to simulator
+ //! \remark does not send if there is no change
+ bool sendRemoteAircraftPartsToSimulator(const CSimConnectObject &simObject,
+ const swift::misc::aviation::CAircraftParts &parts);
+
+ //! Send ATC data (callsign etc.) to simulator
+ bool sendRemoteAircraftAtcDataToSimulator(const CSimConnectObject &simObject);
+
+ //! Call CSimulatorFsxCommon::updateRemoteAircraftFromSimulator asynchronously
+ //! \remark do not to send SimConnect data in event loop
+ void triggerUpdateRemoteAircraftFromSimulator(const CSimConnectObject &simObject,
+ const DataDefinitionPosData &remoteAircraftData);
+
+ //! Call CSimulatorFsxCommon::updateRemoteAircraftFromSimulator asynchronously
+ //! \remark do not to send SimConnect data in event loop
+ void triggerUpdateRemoteAircraftFromSimulator(const CSimConnectObject &simObject,
+ const DataDefinitionRemoteAircraftModel &remoteAircraftModel);
+
+ //! Remote aircraft data sent from simulator
+ void updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject,
+ const DataDefinitionPosData &remoteAircraftData);
+
+ //! Remote aircraft data sent from simulator
+ void updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject,
+ const DataDefinitionRemoteAircraftModel &remoteAircraftModel);
+
+ //! Probe data sent from simulator
+ void updateProbeFromSimulator(const swift::misc::aviation::CCallsign &callsign,
+ const DataDefinitionPosData &remoteAircraftData);
+
+ //! Customization point for adjusting altitude to compensate for temperature effect
+ virtual void
+ setTrueAltitude(swift::misc::aviation::CAircraftSituation &aircraftSituation,
+ const swift::simplugin::msfs2024common::DataDefinitionOwnAircraft &simulatorOwnAircraft);
+
+ //! Called when data about our own aircraft are received
+ void updateOwnAircraftFromSimulator(const DataDefinitionOwnAircraft &simulatorOwnAircraft);
+
+ //! Update from SB client area
+ //! \threadsafe
+ void updateOwnAircraftFromSimulator(const DataDefinitionClientAreaSb &sbDataArea);
+
+ //! Update transponder mode
+ //! \threadsafe
+ void updateTransponderMode(const misc::aviation::CTransponder::TransponderMode xpdrMode);
+
+ //! Update transponder mode from MSFS
+ void updateMSFS2024TransponderMode(const DataDefinitionMSFSTransponderMode transponderMode);
+
+ //! An AI aircraft was added in the simulator
+ bool simulatorReportedObjectAdded(DWORD objectId);
+
+ //! Simulator reported that AI aircraft was removed
+ bool simulatorReportedObjectRemoved(DWORD objectID);
+
+ //! Set ID of a SimConnect object, so far we only have an request id in the object
+ bool setSimConnectObjectId(DWORD requestId, DWORD objectId);
+
+ //! Remember current lights
+ bool setCurrentLights(const swift::misc::aviation::CCallsign &callsign,
+ const swift::misc::aviation::CAircraftLights &lights);
+
+ //! Remember lights sent
+ bool setLightsAsSent(const swift::misc::aviation::CCallsign &callsign,
+ const swift::misc::aviation::CAircraftLights &lights);
+
+ //! Display receive exceptions?
+ bool stillDisplayReceiveExceptions();
+
+ //! The SimConnect related objects
+ const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; }
+
+ //! The SimConnect object for idxs
+ CSimConnectObject getSimObjectForObjectId(DWORD objectId) const;
+
+ //! Request data for a CSimConnectObject (aka remote aircraft)
+ bool requestPositionDataForSimObject(const CSimConnectObject &simObject,
+ SIMCONNECT_PERIOD period = SIMCONNECT_PERIOD_SECOND);
+
+ //! Request lights for a CSimConnectObject
+ bool requestLightsForSimObject(const CSimConnectObject &simObject);
+
+ //! Model info for a CSimConnectObject
+ bool requestModelInfoForSimObject(const CSimConnectObject &simObject);
+
+ //! Stop requesting data for CSimConnectObject
+ bool stopRequestingDataForSimObject(const CSimConnectObject &simObject);
+
+ //! FSX position as string
+ static QString fsxPositionToString(const SIMCONNECT_DATA_INITPOSITION &position);
+
+ //! Get the callsigns which are no longer in the provider, but still in m_simConnectObjects
+ swift::misc::aviation::CCallsignSet getCallsignsMissingInProvider() const;
+
+ //! Set tracing on/off
+ void setTraceSendId(bool traceSendId) { m_traceSendId = traceSendId; }
+
+ //! Trace the send id
+ void traceSendId(const CSimConnectObject &simObject, const QString &functionName, const QString &details = {},
+ bool forceTrace = false);
+
+ //! Send id trace or given send id
+ TraceFsxSendId getSendIdTrace(DWORD sendId) const;
+
+ //! Get the trace details, otherwise empty string
+ QString getSendIdTraceDetails(const TraceFsxSendId &trace) const;
+
+ //! Get the trace details, otherwise empty string
+ QString getSendIdTraceDetails(DWORD sendId) const;
+
+ //! Remove all probes
+ int removeAllProbes();
+
+ //! Insert a new SimConnect object
+ CSimConnectObject insertNewSimConnectObject(const swift::misc::simulation::CSimulatedAircraft &aircraft,
+ DWORD requestId, CSimConnectObject::SimObjectType type,
+ const CSimConnectObject &removedPendingObject = {});
+
+ //! Update simulator COM from swift data. Returns true if simulator frequency was changed
+ bool updateCOMFromSwiftToSimulator(const swift::misc::physical_quantities::CFrequency &newFreq,
+ const swift::misc::physical_quantities::CFrequency &lastSimFreq,
+ swift::misc::physical_quantities::CFrequency &last25kHzSimFreq, EventIds id);
+
+ //! Used for terrain probes
+ static const swift::misc::aviation::CAltitude &terrainProbeAltitude();
+
+ static constexpr int GuessRemoteAircraftPartsCycle = 20; //!< guess every n-th cycle
+ static constexpr int SkipUpdateCyclesForCockpit = 10; //!< skip x cycles before updating cockpit again
+ static constexpr int IgnoreReceiveExceptions = 10; //!< skip exceptions when displayed more than x times
+ static constexpr int MaxSendIdTraces = 10000; //!< max.traces of send id
+ static constexpr DWORD MaxSimObjAircraft = 10000; //!< max.number of SimObjects at the same time
+ static constexpr DWORD MaxSimObjProbes = 100; //!< max. probes
+
+ // -- second chance tresholds --
+ static constexpr int ThresholdAddException = 1; //!< one failure allowed
+ static constexpr int ThresholdAddedAndDirectlyRemoved = 2; //!< two failures allowed
+
+ // -- range for sim data, each sim object will get its own request id and use the offset ranges
+ static constexpr int RequestSimObjAircraftStart = static_cast(CSimConnectDefinitions::RequestEndMarker);
+ static constexpr int RequestSimObjAircraftEnd = RequestSimObjAircraftStart - 1 + MaxSimObjAircraft;
+ static constexpr int RequestSimObjAircraftRangeEnd =
+ RequestSimObjAircraftStart - 1 +
+ static_cast(CSimConnectDefinitions::SimObjectEndMarker) * MaxSimObjAircraft;
+
+ // times
+ static constexpr int AddPendingAircraftIntervalMs = 10 * 1000;
+ static constexpr int DispatchIntervalMs = 10; //!< how often with run the FSX event queue
+ static constexpr int DeferSimulatingFlagMs =
+ 1500; //!< simulating can jitter at startup (simulating->stopped->simulating, multiple start events), so we
+ //!< defer detection
+ static constexpr int DeferResendingLights =
+ 2500; //!< Resend light state when aircraft light state was not yet available
+
+ QString m_simConnectVersion; //!< SimConnect version
+ bool m_simConnected = false; //!< Is simulator connected?
+ bool m_simSimulating = false; //!< Simulator running?
+ bool m_useSbOffsets = true; //!< with SB offsets
+ bool m_logSbOffsets = false; //!< log SB offsets
+ bool m_traceSendId = false; //!< trace the send ids, meant for debugging
+ bool m_useAddSimulatedObj = false; //!< simulated object use if AI Non ATC object fails
+ qint64 m_traceAutoUntilTs = -1; //!< allows to automatically trace for some time
+ qint64 m_simulatingChangedTs = -1; //!< timestamp, when simulating changed (used to avoid jitter)
+ int m_sbDataReceived = 0; //!< SB3 area data received
+
+ // tracing dispatch performance
+ int m_dispatchErrors = 0; //!< number of dispatched failed, \sa dispatch
+ int m_dispatchProcCount = 0; //!< number of dispatchProc counts
+ int m_dispatchProcEmptyCount = 0; //!< number dispatchProc doing nothing
+ qint64 m_dispatchTimeMs = -1; //!< \sa ISimulator::getStatisticsSimulatorSpecific
+ qint64 m_dispatchMaxTimeMs = -1; //!< \sa ISimulator::getStatisticsSimulatorSpecific
+ qint64 m_dispatchProcTimeMs = -1; //!< \sa ISimulator::getStatisticsSimulatorSpecific
+ qint64 m_dispatchProcMaxTimeMs = -1; //!< \sa ISimulator::getStatisticsSimulatorSpecific
+
+ SIMCONNECT_RECV_ID m_dispatchReceiveIdLast = SIMCONNECT_RECV_ID_NULL; //!< last receive id from dispatching
+ SIMCONNECT_RECV_ID m_dispatchReceiveIdMaxTime =
+ SIMCONNECT_RECV_ID_NULL; //!< receive id corresponding to max.time
+ DWORD m_dispatchRequestIdLast =
+ CSimConnectDefinitions::RequestEndMarker; //!< request id if any for last request
+ DWORD m_dispatchRequestIdMaxTime =
+ CSimConnectDefinitions::RequestEndMarker; //!< request id corresponding to max.time
+
+ // sending via SimConnect
+ QList m_sendIdTraces; //!< Send id traces for debugging, latest first
+ int m_receiveExceptionCount = 0; //!< exceptions
+ int m_requestSimObjectDataCount = 0; //!< requested SimObjects
+
+ // settings
+ swift::misc::simulation::settings::CMultiSimulatorDetailsSettings m_detailsSettings;
+
+ // objects
+ CSimConnectObjects m_simConnectObjectsPositionAndPartsTraces; //!< position/parts received, but object not yet
+ //!< added, excluded, disabled etc.
+ CSimConnectObjects m_addPendingAircraft; //!< aircraft/probes awaiting to be added;
+ SIMCONNECT_DATA_REQUEST_ID m_requestIdSimObjAircraft = static_cast(
+ RequestSimObjAircraftStart); //!< request id, use obtainRequestIdForSimObjAircraft to get id
+ QTimer m_simObjectTimer; //!< updating of SimObjects awaiting to be added
+
+ // Last selected frequencies in simulator before setting 8.33 kHz spacing frequency
+ swift::misc::physical_quantities::CFrequency m_lastCom1Active {
+ 0, swift::misc::physical_quantities::CFrequencyUnit::nullUnit()
+ }; //!< last COM1 active frequency
+ swift::misc::physical_quantities::CFrequency m_lastCom1Standby {
+ 0, swift::misc::physical_quantities::CFrequencyUnit::nullUnit()
+ }; //!< last COM1 standby frequency
+ swift::misc::physical_quantities::CFrequency m_lastCom2Active {
+ 0, swift::misc::physical_quantities::CFrequencyUnit::nullUnit()
+ }; //!< last COM2 active frequency
+ swift::misc::physical_quantities::CFrequency m_lastCom2Standby {
+ 0, swift::misc::physical_quantities::CFrequencyUnit::nullUnit()
+ }; //!< last COM2 standby frequency
+
+ //! Request id to string
+ static QString requestIdToString(DWORD requestId);
+
+ //! status of loaded sim objects
+ sSimmobjectLoaded sSimmobjectLoadedState;
+
+ //! cached sim objects and liveries read frim simconnect
+ std::vector vSimObjectsAndLiveries;
+
+ //! Simulator info
+ swift::misc::simulation::CSimulatorInfo m_simulatorInfo;
+
+ swift::misc::CSetting m_matchingSettings {
+ this
+ }; //!< settings
+
+ public:
+ //! @{
+ //! Offsets
+ static DWORD offsetSimObjAircraft(CSimConnectDefinitions::SimObjectRequest req)
+ {
+ return MaxSimObjAircraft * static_cast(req);
+ }
+ //! @}
+ };
+
+ //! Listener for MSFS2024
+ class MSFS2024_EXPORT CSimulatorMsfs2024Listener : public swift::core::ISimulatorListener
+ {
+ Q_OBJECT
+
+ public:
+ //! Constructor
+ CSimulatorMsfs2024Listener(const swift::misc::simulation::CSimulatorPluginInfo &info);
+
+ //! \copydoc swift::core::ISimulatorListener::backendInfo
+ virtual QString backendInfo() const override;
+
+ protected:
+ //! \copydoc swift::core::ISimulatorListener::startImpl
+ virtual void startImpl() override;
+
+ //! \copydoc swift::core::ISimulatorListener::stopImpl
+ virtual void stopImpl() override;
+
+ //! \copydoc swift::core::ISimulatorListener::checkImpl
+ virtual void checkImpl() override;
+
+ private:
+ //! Test if connection can be established
+ void checkConnection();
+
+ //! Check simulator version and type
+ bool checkVersionAndSimulator() const;
+
+ //! Check the simconnect.dll
+ bool checkSimConnectDll() const;
+
+ //! Connect to simulator (if not already)
+ bool connectToSimulator();
+
+ //! Disconnect from simulator
+ bool disconnectFromSimulator();
+
+ //! Adjust the timer interval
+ void adjustTimerInterval(qint64 checkTimeMs);
+
+ static constexpr int MinQueryIntervalMs = 5 * 1000; // 5 seconds
+
+ QTimer m_timer { this }; //!< timer, "this" is needed otherwise I get warnings when move to new thread
+ QString m_simulatorVersion;
+ QString m_simConnectVersion;
+ QString m_simulatorName;
+ QString m_simulatorDetails;
+ HANDLE m_hSimConnect;
+ bool m_simConnected = false; //!< SimConnect is connected, does not mean to the correct sim.
+ swift::misc::CStatusMessage m_lastMessage; //!< last listener message
+
+ //! SimConnect Callback (simplified version for listener)
+ //! \sa CSimConnectObjects::SimConnectProc
+ static void CALLBACK SimConnectProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext);
+ };
+} // namespace swift::simplugin::msfs2024common
+
+#endif // SWIFT_SIMPLUGIN_MSFS2024COMMON_SIMULATORMSFS2024COMMON_H
diff --git a/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp
new file mode 100644
index 000000000..0d94a4cb0
--- /dev/null
+++ b/src/plugins/simulator/msfs2024/simulatormsfs2024simconnectproc.cpp
@@ -0,0 +1,426 @@
+// 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 = false;
+
+ 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_DATA_ERROR:
+ logGenericExceptionInfo = true;
+ break; // data error, can happen during data request
+ 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())
+ {
+ CLogMessage(simulatorMsfs2024).warning(u"Adding Aircraft failed: %1 %2")
+ << simObject.getCallsign().asString() << simObject.getAircraftModelString();
+ 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();
+ logGenericExceptionInfo = false;
+ } // aircraft
+ } // valid
+ } // trace
+ } // SIMCONNECT_EXCEPTION_CREATE_OBJECT_FAILED:
+ break;
+ default: logGenericExceptionInfo = true; 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;
+
+ 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) == 60 * 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->updateMSFS2024TransponderMode(*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 + 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) == 9 * 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();
+ }
+ }
+ }
+ }
+ 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_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/plugins/simulator/xplane/simulatorxplane.cpp b/src/plugins/simulator/xplane/simulatorxplane.cpp
index 3c76ea07f..5179e3f03 100644
--- a/src/plugins/simulator/xplane/simulatorxplane.cpp
+++ b/src/plugins/simulator/xplane/simulatorxplane.cpp
@@ -402,7 +402,8 @@ namespace swift::simplugin::xplane
// Engine number start counting at 1
// We consider the engine running when N1 is bigger than 5 %
const CAircraftEngine engine { engineNumber + 1,
- m_xplaneData.enginesN1Percentage.at(engineNumber) > 5.0 };
+ m_xplaneData.enginesN1Percentage.at(engineNumber) > 5.0,
+ static_cast(m_xplaneData.enginesN1Percentage.at(engineNumber)) };
engines.push_back(engine);
}
diff --git a/src/xswiftbus/xplanemp2 b/src/xswiftbus/xplanemp2
index 0f81fd117..8b07d1daf 160000
--- a/src/xswiftbus/xplanemp2
+++ b/src/xswiftbus/xplanemp2
@@ -1 +1 @@
-Subproject commit 0f81fd117a56ff3812eb8d2bcee69254330e78ae
+Subproject commit 8b07d1daf8283cad8c0cf401e5ddf7f3f11a9b70
diff --git a/tests/misc/aviation/testaircraftparts/testaircraftparts.cpp b/tests/misc/aviation/testaircraftparts/testaircraftparts.cpp
index f754a811a..395c33be1 100644
--- a/tests/misc/aviation/testaircraftparts/testaircraftparts.cpp
+++ b/tests/misc/aviation/testaircraftparts/testaircraftparts.cpp
@@ -77,7 +77,7 @@ namespace MiscTest
{
const CAircraftLights lights = CAircraftLights::allLightsOn();
CAircraftEngineList engines;
- engines.initEngines(4, true);
+ engines.initEngines(4, true, 100);
const bool onGround = true;
CAircraftParts ap(lights, true, 0, false, engines, onGround);
return ap;
diff --git a/tests/misc/simulation/testinterpolatorlinear/testinterpolatorlinear.cpp b/tests/misc/simulation/testinterpolatorlinear/testinterpolatorlinear.cpp
index c3d972067..1f2aa1ab7 100644
--- a/tests/misc/simulation/testinterpolatorlinear/testinterpolatorlinear.cpp
+++ b/tests/misc/simulation/testinterpolatorlinear/testinterpolatorlinear.cpp
@@ -204,7 +204,8 @@ namespace MiscTest
CAircraftParts CTestInterpolatorLinear::getTestParts(int number, qint64 ts, qint64 deltaT)
{
CAircraftLights l(true, false, true, false, true, false);
- CAircraftEngineList e({ CAircraftEngine(1, true), CAircraftEngine(2, false), CAircraftEngine(3, true) });
+ CAircraftEngineList e(
+ { CAircraftEngine(1, true, 100), CAircraftEngine(2, false, 0), CAircraftEngine(3, true, 100) });
CAircraftParts p(l, true, 20, true, e, false);
p.setMSecsSinceEpoch(ts - deltaT * number); // values in past
return p;
diff --git a/tests/misc/simulation/testinterpolatorparts/testinterpolatorparts.cpp b/tests/misc/simulation/testinterpolatorparts/testinterpolatorparts.cpp
index afd5e257c..f1b750bfe 100644
--- a/tests/misc/simulation/testinterpolatorparts/testinterpolatorparts.cpp
+++ b/tests/misc/simulation/testinterpolatorparts/testinterpolatorparts.cpp
@@ -163,7 +163,8 @@ namespace MiscTest
CAircraftParts CTestInterpolatorParts::createTestParts(int number, qint64 ts, qint64 deltaT, bool onGround)
{
CAircraftLights l(true, false, true, false, true, false);
- CAircraftEngineList e({ CAircraftEngine(1, true), CAircraftEngine(2, false), CAircraftEngine(3, true) });
+ CAircraftEngineList e(
+ { CAircraftEngine(1, true, 100), CAircraftEngine(2, false, 0), CAircraftEngine(3, true, 100) });
CAircraftParts p(l, true, 20, true, e, false);
p.setMSecsSinceEpoch(ts - deltaT * number); // values in past
p.setTimeOffsetMs(0);