refs #789, improvements to try to solve FSX issue in driver

* more asserts to find issues
* limit number of exceptions displayed
* reset() function (there was an issue with not cleaned up values)
* using CSimConnectObjects and adjustments for the previous changes
This commit is contained in:
Klaus Basan
2016-11-07 20:22:15 +01:00
parent 9deedf1e10
commit 94d6b8d6b8
9 changed files with 379 additions and 171 deletions

View File

@@ -18,6 +18,7 @@
#include "blackcore/application.h" #include "blackcore/application.h"
#include "blackcore/pluginmanagersimulator.h" #include "blackcore/pluginmanagersimulator.h"
#include "blackcore/simulator.h" #include "blackcore/simulator.h"
#include "blackmisc/verify.h"
#include "blackmisc/aviation/callsign.h" #include "blackmisc/aviation/callsign.h"
#include "blackmisc/compare.h" #include "blackmisc/compare.h"
#include "blackmisc/dbusserver.h" #include "blackmisc/dbusserver.h"
@@ -494,9 +495,10 @@ namespace BlackCore
void CContextSimulator::ps_addedRemoteAircraft(const CSimulatedAircraft &remoteAircraft) void CContextSimulator::ps_addedRemoteAircraft(const CSimulatedAircraft &remoteAircraft)
{ {
if (!isSimulatorSimulating()) { return; } if (!isSimulatorSimulating()) { return; }
Q_ASSERT(!remoteAircraft.getCallsign().isEmpty());
const CCallsign callsign = remoteAircraft.getCallsign(); const CCallsign callsign = remoteAircraft.getCallsign();
BLACK_VERIFY_X(!callsign.isEmpty(), Q_FUNC_INFO, "Remote aircrft with empty callsign");
if (callsign.isEmpty()) { return; }
CStatusMessageList matchingMessages; CStatusMessageList matchingMessages;
CStatusMessageList *pMatchingMessages = m_enableMatchingMessages ? &matchingMessages : nullptr; CStatusMessageList *pMatchingMessages = m_enableMatchingMessages ? &matchingMessages : nullptr;
const CAircraftModel aircraftModel = m_modelMatcher.getClosestMatch(remoteAircraft, pMatchingMessages); const CAircraftModel aircraftModel = m_modelMatcher.getClosestMatch(remoteAircraft, pMatchingMessages);

View File

@@ -80,12 +80,14 @@ namespace BlackCore
bool CSimulatorCommon::logicallyAddRemoteAircraft(const CSimulatedAircraft &remoteAircraft) bool CSimulatorCommon::logicallyAddRemoteAircraft(const CSimulatedAircraft &remoteAircraft)
{ {
Q_ASSERT_X(remoteAircraft.hasModelString(), Q_FUNC_INFO, "Missing model string");
Q_ASSERT_X(remoteAircraft.hasCallsign(), Q_FUNC_INFO, "Missing callsign");
if (!remoteAircraft.isEnabled()) { return false; } if (!remoteAircraft.isEnabled()) { return false; }
// if not restriced, directly change // if not restriced, directly change
if (!isRenderingRestricted()) { this->physicallyAddRemoteAircraft(remoteAircraft); return true; } if (!isRenderingRestricted()) { this->physicallyAddRemoteAircraft(remoteAircraft); return true; }
// will be added with next snapshot // will be added with next snapshot ps_recalculateRenderedAircraft
return false; return false;
} }
@@ -94,7 +96,7 @@ namespace BlackCore
// if not restriced, directly change // if not restriced, directly change
if (!isRenderingRestricted()) { this->physicallyRemoveRemoteAircraft(callsign); return true; } if (!isRenderingRestricted()) { this->physicallyRemoveRemoteAircraft(callsign); return true; }
// will be added with next snapshot // will be added with next snapshot ps_recalculateRenderedAircraft
return false; return false;
} }
@@ -322,11 +324,11 @@ namespace BlackCore
void CSimulatorCommon::highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime) void CSimulatorCommon::highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime)
{ {
CCallsign cs(aircraftToHighlight.getCallsign()); const CCallsign cs(aircraftToHighlight.getCallsign());
this->m_highlightedAircraft.removeByCallsign(cs); this->m_highlightedAircraft.removeByCallsign(cs);
if (enableHighlight) if (enableHighlight)
{ {
qint64 deltaT = displayTime.valueRounded(CTimeUnit::ms(), 0); const qint64 deltaT = displayTime.valueRounded(CTimeUnit::ms(), 0);
this->m_highlightEndTimeMsEpoch = QDateTime::currentMSecsSinceEpoch() + deltaT; this->m_highlightEndTimeMsEpoch = QDateTime::currentMSecsSinceEpoch() + deltaT;
this->m_highlightedAircraft.push_back(aircraftToHighlight); this->m_highlightedAircraft.push_back(aircraftToHighlight);
} }
@@ -432,4 +434,36 @@ namespace BlackCore
{ {
Q_UNUSED(callsign); Q_UNUSED(callsign);
} }
void CSimulatorCommon::ps_queueForAdding(const CSimulatedAircraft &aircraft)
{
m_pendingAircraftToAdd.replaceOrAddByCallsign(aircraft);
QTimer::singleShot(500, this, [ = ]
{
this->physicallyAddNextQueuedAircraft();
});
}
void CSimulatorCommon::physicallyAddNextQueuedAircraft()
{
if (m_pendingAircraftToAdd.isEmpty()) { return; } // delete in meantime
CSimulatedAircraft nextAircraft(m_pendingAircraftToAdd.front()); // normally it should always find a value
m_pendingAircraftToAdd.pop_front();
this->physicallyAddRemoteAircraft(nextAircraft);
}
void CSimulatorCommon::reset()
{
m_statsUpdateAircraftCountMs = 0;
m_statsUpdateAircraftTimeAvgMs = 0;
m_statsUpdateAircraftTimeTotalMs = 0;
this->clearAllAircraft();
}
void CSimulatorCommon::clearAllAircraft()
{
m_aircraftToAddAgainWhenRemoved.clear();
m_pendingAircraftToAdd.clear();
}
} // namespace } // namespace

View File

@@ -88,6 +88,8 @@ namespace BlackCore
//! @} //! @}
protected slots: protected slots:
//! \name Connected with remote aircraft provider signals {
//! Slow timer used to highlight aircraft, can be used for other things too //! Slow timer used to highlight aircraft, can be used for other things too
virtual void ps_oneSecondTimer(); virtual void ps_oneSecondTimer();
@@ -102,6 +104,11 @@ namespace BlackCore
//! Provider removed aircraft //! Provider removed aircraft
virtual void ps_remoteProviderRemovedAircraft(const BlackMisc::Aviation::CCallsign &callsign); virtual void ps_remoteProviderRemovedAircraft(const BlackMisc::Aviation::CCallsign &callsign);
//! @}
//! Add when pending aircraft is added
//! \remark no need to use this if multiple models can be added to simulator at once
void ps_queueForAdding(const BlackMisc::Simulation::CSimulatedAircraft &aircraft);
protected: protected:
//! Constructor //! Constructor
@@ -117,6 +124,12 @@ namespace BlackCore
//! \copydoc ISimulator::logicallyRemoveRemoteAircraft //! \copydoc ISimulator::logicallyRemoveRemoteAircraft
virtual bool logicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override; virtual bool logicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override;
//! Reset state
virtual void reset();
//! Clear all aircraft related data
virtual void clearAllAircraft();
//! Blink the highlighted aircraft //! Blink the highlighted aircraft
void blinkHighlightedAircraft(); void blinkHighlightedAircraft();
@@ -132,15 +145,22 @@ namespace BlackCore
//! Set own model //! Set own model
void reverseLookupAndUpdateOwnAircraftModel(const QString &modelString); void reverseLookupAndUpdateOwnAircraftModel(const QString &modelString);
protected: //! Add the next qeueud aircraft
void physicallyAddNextQueuedAircraft();
BlackMisc::IInterpolator *m_interpolator = nullptr; //!< interpolator instance BlackMisc::IInterpolator *m_interpolator = nullptr; //!< interpolator instance
bool m_pausedSimFreezesInterpolation = false; //!< paused simulator will also pause interpolation (so AI aircraft will hold) bool m_pausedSimFreezesInterpolation = false; //!< paused simulator will also pause interpolation (so AI aircraft will hold)
BlackMisc::Simulation::CSimulatorSetup m_simulatorSetup; //!< setup object BlackMisc::Simulation::CSimulatorSetup m_simulatorSetup; //!< setup object
BlackMisc::CInterpolationAndRenderingSetup m_interpolationRenderingSetup; //!< debug messages, rendering etc.
BlackMisc::Simulation::CAircraftModel m_defaultModel; //!< default model BlackMisc::Simulation::CAircraftModel m_defaultModel; //!< default model
qint64 m_statsUpdateAircraftTimeTotalMs = 0; //!< statistics update time qint64 m_statsUpdateAircraftTimeTotalMs = 0; //!< statistics update time
qint64 m_statsUpdateAircraftTimeAvgMs = 0; //!< statistics update time qint64 m_statsUpdateAircraftTimeAvgMs = 0; //!< statistics update time
int m_statsUpdateAircraftCountMs = 0; //!< statistics update time int m_statsUpdateAircraftCountMs = 0; //!< statistics update time
// some optional functionality which can be used by the sims as needed
BlackMisc::Simulation::CSimulatedAircraftList m_aircraftToAddAgainWhenRemoved; //!< add this model again when removed, normally used to change model
BlackMisc::Simulation::CSimulatedAircraftList m_pendingAircraftToAdd; //!< used with qeued adding, here only one model is added add a time and only after it is confirmed by the sim. the next model is added
//! Lookup against DB data //! Lookup against DB data
static BlackMisc::Simulation::CAircraftModel reverseLookupModel(const BlackMisc::Simulation::CAircraftModel &model); static BlackMisc::Simulation::CAircraftModel reverseLookupModel(const BlackMisc::Simulation::CAircraftModel &model);

View File

@@ -106,7 +106,8 @@ namespace BlackSimPlugin
{ {
connect(lobbyClient.data(), &CLobbyClient::disconnected, this, std::bind(&CSimulatorFs9::simulatorStatusChanged, this, 0)); connect(lobbyClient.data(), &CLobbyClient::disconnected, this, std::bind(&CSimulatorFs9::simulatorStatusChanged, this, 0));
this->m_interpolator = new BlackMisc::CInterpolatorLinear(remoteAircraftProvider, this); this->m_interpolator = new BlackMisc::CInterpolatorLinear(remoteAircraftProvider, this);
m_defaultModel = { m_defaultModel =
{
"Boeing 737-400", "Boeing 737-400",
CAircraftModel::TypeModelMatchingDefaultModel, CAircraftModel::TypeModelMatchingDefaultModel,
"B737-400 default model", "B737-400 default model",
@@ -170,10 +171,13 @@ namespace BlackSimPlugin
client->start(); client->start();
m_hashFs9Clients.insert(callsign, client); m_hashFs9Clients.insert(callsign, client);
updateAircraftRendered(callsign, rendered); bool updated = updateAircraftRendered(callsign, rendered);
CSimulatedAircraft remoteAircraftCopy(newRemoteAircraft); CSimulatedAircraft remoteAircraftCopy(newRemoteAircraft);
remoteAircraftCopy.setRendered(rendered); remoteAircraftCopy.setRendered(rendered);
emit aircraftRenderingChanged(remoteAircraftCopy); if (updated)
{
emit aircraftRenderingChanged(remoteAircraftCopy);
}
CLogMessage(this).info("FS9: Added aircraft %1") << callsign.toQString(); CLogMessage(this).info("FS9: Added aircraft %1") << callsign.toQString();
return true; return true;
} }

View File

@@ -26,7 +26,7 @@ namespace BlackSimPlugin
{ {
namespace Fsx namespace Fsx
{ {
//! \brief Data struct of our own aircraft //! Data struct of our own aircraft
//! \sa SimConnect variables http://msdn.microsoft.com/en-us/library/cc526981.aspx //! \sa SimConnect variables http://msdn.microsoft.com/en-us/library/cc526981.aspx
//! \sa SimConnect events http://msdn.microsoft.com/en-us/library/cc526980.aspx //! \sa SimConnect events http://msdn.microsoft.com/en-us/library/cc526980.aspx
struct DataDefinitionOwnAircraft struct DataDefinitionOwnAircraft
@@ -40,12 +40,12 @@ namespace BlackSimPlugin
double velocity; //!< Ground velocity double velocity; //!< Ground velocity
double simOnGround; //!< Is aircraft on ground? double simOnGround; //!< Is aircraft on ground?
double lightStrobe; //!< Is strobe light on? double lightStrobe; //!< Is strobe light on?
double lightLanding; //!< Is landing light on? double lightLanding; //!< Is landing light on?
double lightTaxi; //!< Is taxi light on? double lightTaxi; //!< Is taxi light on?
double lightBeacon; //!< Is beacon light on? double lightBeacon; //!< Is beacon light on?
double lightNav; //!< Is nav light on? double lightNav; //!< Is nav light on?
double lightLogo; //!< Is logo light on? double lightLogo; //!< Is logo light on?
double transponderCode; //!< Transponder Code double transponderCode; //!< Transponder Code
double com1ActiveMHz; //!< COM1 active frequency double com1ActiveMHz; //!< COM1 active frequency
@@ -73,22 +73,22 @@ namespace BlackSimPlugin
//! Data struct of remote aircraft parts //! Data struct of remote aircraft parts
struct DataDefinitionRemoteAircraftParts struct DataDefinitionRemoteAircraftParts
{ {
double lightStrobe; //!< Is strobe light on? double lightStrobe; //!< Is strobe light on?
double lightLanding; //!< Is landing light on? double lightLanding; //!< Is landing light on?
// double lightTaxi; //!< Is taxi light on? // double lightTaxi; //!< Is taxi light on?
double lightBeacon; //!< Is beacon light on? double lightBeacon; //!< Is beacon light on?
double lightNav; //!< Is nav light on? double lightNav; //!< Is nav light on?
double lightLogo; //!< Is logo light on? double lightLogo; //!< Is logo light on?
double flapsLeadingEdgeLeftPercent; //!< Leading edge left in percent double flapsLeadingEdgeLeftPercent; //!< Leading edge left in percent
double flapsLeadingEdgeRightPercent; //!< Leading edge right in percent double flapsLeadingEdgeRightPercent; //!< Leading edge right in percent
double flapsTrailingEdgeLeftPercent; //!< Trailing edge left in percent double flapsTrailingEdgeLeftPercent; //!< Trailing edge left in percent
double flapsTrailingEdgeRightPercent; //!< Trailing edge right in percent double flapsTrailingEdgeRightPercent; //!< Trailing edge right in percent
double gearHandlePosition; //!< Gear handle position double gearHandlePosition; //!< Gear handle position
double spoilersHandlePosition; //!< Spoilers out? double spoilersHandlePosition; //!< Spoilers out?
double engine1Combustion; //!< Engine 1 combustion flag double engine1Combustion; //!< Engine 1 combustion flag
double engine2Combustion; //!< Engine 2 combustion flag double engine2Combustion; //!< Engine 2 combustion flag
double engine3Combustion; //!< Engine 3 combustion flag double engine3Combustion; //!< Engine 3 combustion flag
double engine4Combustion; //!< Engine 4 combustion flag double engine4Combustion; //!< Engine 4 combustion flag
}; };
//! Data struct simulator environment //! Data struct simulator environment
@@ -134,7 +134,6 @@ namespace BlackSimPlugin
class CSimConnectDefinitions class CSimConnectDefinitions
{ {
public: public:
//! SimConnect definiton IDs //! SimConnect definiton IDs
enum DataDefiniton enum DataDefiniton
{ {
@@ -168,7 +167,6 @@ namespace BlackSimPlugin
static QString getLogCategory() { return "swift.fsx.simconnect"; } static QString getLogCategory() { return "swift.fsx.simconnect"; }
private: private:
//! Initialize data definition for our own aircraft //! Initialize data definition for our own aircraft
static HRESULT initOwnAircraft(const HANDLE hSimConnect); static HRESULT initOwnAircraft(const HANDLE hSimConnect);

View File

@@ -40,6 +40,9 @@ namespace BlackSimPlugin
//! Simulated aircraft (as added) //! Simulated aircraft (as added)
const BlackMisc::Simulation::CSimulatedAircraft &getAircraft() const { return m_aircraft; } const BlackMisc::Simulation::CSimulatedAircraft &getAircraft() const { return m_aircraft; }
//! Simulated aircraft model string
const QString &getAircraftModelString() const { return m_aircraft.getModelString(); }
//! Set Simconnect request id //! Set Simconnect request id
void setRequestId(int id) { m_requestId = id; } void setRequestId(int id) { m_requestId = id; }

View File

@@ -19,6 +19,7 @@
#include "blackmisc/aviation/airportlist.h" #include "blackmisc/aviation/airportlist.h"
#include "blackmisc/logmessage.h" #include "blackmisc/logmessage.h"
#include "blackmisc/threadutils.h" #include "blackmisc/threadutils.h"
#include "blackmisc/verify.h"
#include "blackmisc/simulation/fscommon/fscommonutil.h" #include "blackmisc/simulation/fscommon/fscommonutil.h"
#include <QTimer> #include <QTimer>
@@ -81,12 +82,10 @@ namespace BlackSimPlugin
bool CSimulatorFsx::connectTo() bool CSimulatorFsx::connectTo()
{ {
if (this->isConnected()) { return true; } if (this->isConnected()) { return true; }
this->reset();
if (FAILED(SimConnect_Open(&m_hSimConnect, sApp->swiftVersionChar(), nullptr, 0, 0, 0))) if (FAILED(SimConnect_Open(&m_hSimConnect, sApp->swiftVersionChar(), nullptr, 0, 0, 0)))
{ {
// reset state as expected for unconnected // reset state as expected for unconnected
if (m_simconnectTimerId >= 0) { killTimer(m_simconnectTimerId); }
m_simConnected = false;
m_simSimulating = false;
return false; return false;
} }
if (m_useFsuipc) { this->m_fsuipc->connect(); } // FSUIPC too if (m_useFsuipc) { this->m_fsuipc->connect(); } // FSUIPC too
@@ -102,25 +101,14 @@ namespace BlackSimPlugin
bool CSimulatorFsx::disconnectFrom() bool CSimulatorFsx::disconnectFrom()
{ {
if (!m_simConnected) { return true; } if (!m_simConnected) { return true; }
if (m_simconnectTimerId) { killTimer(m_simconnectTimerId); }
// stop mapper init
//! \todo mapper shutdown in FSX, review keep it?
// mapperInstance()->gracefulShutdown();
if (m_simconnectTimerId)
{
killTimer(m_simconnectTimerId);
}
if (m_hSimConnect) if (m_hSimConnect)
{ {
SimConnect_Close(m_hSimConnect); SimConnect_Close(m_hSimConnect);
m_hSimConnect = nullptr; m_hSimConnect = nullptr;
} }
m_simConnected = false; reset();
m_simSimulating = false;
m_simconnectTimerId = -1;
// emit status and disconnect FSUIPC // emit status and disconnect FSUIPC
CSimulatorFsCommon::disconnectFrom(); CSimulatorFsCommon::disconnectFrom();
@@ -136,8 +124,26 @@ namespace BlackSimPlugin
Q_ASSERT_X(newRemoteAircraft.hasModelString(), Q_FUNC_INFO, "missing model string"); Q_ASSERT_X(newRemoteAircraft.hasModelString(), Q_FUNC_INFO, "missing model string");
if (callsign.isEmpty()) { return false; } if (callsign.isEmpty()) { return false; }
const bool aircraftAlreadyExistsInSim = this->m_simConnectObjects.contains(callsign); // check if we have to do something
if (aircraftAlreadyExistsInSim) if (m_simConnectObjects.contains(callsign))
{
const CSimConnectObject simObj = m_simConnectObjects[callsign];
if (simObj.isPendingAdded())
{
return true; // already pending
}
else
{
// same model, nothing will change, otherwise add again when removed
if (simObj.getAircraft().getModel() != newRemoteAircraft.getModel())
{
m_aircraftToAddAgainWhenRemoved.push_back(newRemoteAircraft);
}
return false;
}
}
if (!m_pendingAircraftToAdd.isEmpty() || m_simConnectObjects.containsPendingAdd())
{ {
const CSimConnectObject simObj = m_simConnectObjects[callsign]; const CSimConnectObject simObj = m_simConnectObjects[callsign];
if (simObj.isPendingAdded()) if (simObj.isPendingAdded())
@@ -164,11 +170,17 @@ namespace BlackSimPlugin
// initial position // initial position
setInitialAircraftSituation(addedAircraft); // set interpolated data/parts if available setInitialAircraftSituation(addedAircraft); // set interpolated data/parts if available
SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxInitPosition(addedAircraft.getSituation()); const int requestId = m_requestId++;
const QByteArray m = aircraftModel.getModelString().toLocal8Bit(); SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxPosition(addedAircraft.getSituation());
const QString modelString(addedAircraft.getModelString());
const QByteArray m(modelString.toLocal8Bit());
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
{
CLogMessage(this).debug() << "physicallyAddRemoteAircraft" << callsign.toQString() << "request" << requestId << "model" << modelString;
CLogMessage(this).debug() << "initial position" << fsxPositionToString(initialPosition);
}
const int requestId = m_requestId;
++m_requestId;
HRESULT hr = SimConnect_AICreateNonATCAircraft(m_hSimConnect, m.constData(), qPrintable(callsign.toQString().left(12)), initialPosition, static_cast<SIMCONNECT_DATA_REQUEST_ID>(requestId)); HRESULT hr = SimConnect_AICreateNonATCAircraft(m_hSimConnect, m.constData(), qPrintable(callsign.toQString().left(12)), initialPosition, static_cast<SIMCONNECT_DATA_REQUEST_ID>(requestId));
if (hr != S_OK) if (hr != S_OK)
{ {
@@ -275,22 +287,13 @@ namespace BlackSimPlugin
SIMCONNECT_TEXT_TYPE type = SIMCONNECT_TEXT_TYPE_PRINT_BLACK; SIMCONNECT_TEXT_TYPE type = SIMCONNECT_TEXT_TYPE_PRINT_BLACK;
switch (message.getSeverity()) switch (message.getSeverity())
{ {
case CStatusMessage::SeverityDebug: case CStatusMessage::SeverityDebug: return;
return; case CStatusMessage::SeverityInfo: type = SIMCONNECT_TEXT_TYPE_PRINT_GREEN; break;
case CStatusMessage::SeverityInfo: case CStatusMessage::SeverityWarning: type = SIMCONNECT_TEXT_TYPE_PRINT_YELLOW; break;
type = SIMCONNECT_TEXT_TYPE_PRINT_GREEN; case CStatusMessage::SeverityError: type = SIMCONNECT_TEXT_TYPE_PRINT_RED; break;
break;
case CStatusMessage::SeverityWarning:
type = SIMCONNECT_TEXT_TYPE_PRINT_YELLOW;
break;
case CStatusMessage::SeverityError:
type = SIMCONNECT_TEXT_TYPE_PRINT_RED;
break;
} }
HRESULT hr = SimConnect_Text( HRESULT hr = SimConnect_Text(m_hSimConnect, type, 7.5, EventTextMessage,
m_hSimConnect, type, 7.5, EventTextMessage, static_cast<DWORD>(m.size()), static_cast<DWORD>(m.size()), m.data());
m.data()
);
Q_UNUSED(hr); Q_UNUSED(hr);
} }
@@ -312,6 +315,12 @@ namespace BlackSimPlugin
return CCallsignSet(this->m_simConnectObjects.keys()); return CCallsignSet(this->m_simConnectObjects.keys());
} }
bool CSimulatorFsx::stillDisplayReceiveExceptions()
{
m_receiveExceptionCount++;
return m_receiveExceptionCount < IgnoreReceiveExceptions;
}
void CSimulatorFsx::setSimConnected() void CSimulatorFsx::setSimConnected()
{ {
m_simConnected = true; m_simConnected = true;
@@ -404,8 +413,7 @@ namespace BlackSimPlugin
simulatorOwnAircraft.lightLogo); simulatorOwnAircraft.lightLogo);
QList<bool> helperList {simulatorOwnAircraft.engine1Combustion != 0, simulatorOwnAircraft.engine2Combustion != 0, QList<bool> helperList {simulatorOwnAircraft.engine1Combustion != 0, simulatorOwnAircraft.engine2Combustion != 0,
simulatorOwnAircraft.engine3Combustion != 0, simulatorOwnAircraft.engine4Combustion != 0 simulatorOwnAircraft.engine3Combustion != 0, simulatorOwnAircraft.engine4Combustion != 0 };
};
CAircraftEngineList engines; CAircraftEngineList engines;
for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index) for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index)
@@ -436,16 +444,16 @@ namespace BlackSimPlugin
// updates // updates
com1.setFrequencyActive(CFrequency(simulatorOwnAircraft.com1ActiveMHz, CFrequencyUnit::MHz())); com1.setFrequencyActive(CFrequency(simulatorOwnAircraft.com1ActiveMHz, CFrequencyUnit::MHz()));
com1.setFrequencyStandby(CFrequency(simulatorOwnAircraft.com1StandbyMHz, CFrequencyUnit::MHz())); com1.setFrequencyStandby(CFrequency(simulatorOwnAircraft.com1StandbyMHz, CFrequencyUnit::MHz()));
bool changedCom1 = myAircraft.getCom1System() != com1; const bool changedCom1 = myAircraft.getCom1System() != com1;
this->m_simCom1 = com1; this->m_simCom1 = com1;
com2.setFrequencyActive(CFrequency(simulatorOwnAircraft.com2ActiveMHz, CFrequencyUnit::MHz())); com2.setFrequencyActive(CFrequency(simulatorOwnAircraft.com2ActiveMHz, CFrequencyUnit::MHz()));
com2.setFrequencyStandby(CFrequency(simulatorOwnAircraft.com2StandbyMHz, CFrequencyUnit::MHz())); com2.setFrequencyStandby(CFrequency(simulatorOwnAircraft.com2StandbyMHz, CFrequencyUnit::MHz()));
bool changedCom2 = myAircraft.getCom2System() != com2; const bool changedCom2 = myAircraft.getCom2System() != com2;
this->m_simCom2 = com2; this->m_simCom2 = com2;
transponder.setTransponderCode(simulatorOwnAircraft.transponderCode); transponder.setTransponderCode(simulatorOwnAircraft.transponderCode);
bool changedXpr = (myAircraft.getTransponderCode() != transponder.getTransponderCode()); const bool changedXpr = (myAircraft.getTransponderCode() != transponder.getTransponderCode());
if (changedCom1 || changedCom2 || changedXpr) if (changedCom1 || changedCom2 || changedXpr)
{ {
@@ -486,60 +494,86 @@ namespace BlackSimPlugin
this->updateCockpit(myAircraft.getCom1System(), myAircraft.getCom2System(), xpdr, this->identifier()); this->updateCockpit(myAircraft.getCom1System(), myAircraft.getCom2System(), xpdr, this->identifier());
} }
bool CSimulatorFsx::aiAircraftWasAddedInSimulator(DWORD requestID, DWORD objectID) bool CSimulatorFsx::simulatorReportedObjectAdded(DWORD objectID)
{ {
if (!this->setSimConnectObjectID(requestID, objectID)) { return false; } const CSimConnectObject simObject = this->m_simConnectObjects.getSimObjectForObjectId(objectID);
const CSimConnectObject simObject = this->getSimObjectForObjectId(objectID); const CCallsign callsign(simObject.getCallsign());
if (!simObject.hasValidRequestAndObjectId() || callsign.isEmpty()) { return false; }
bool ok = false; Q_ASSERT_X(simObject.isPendingAdded(), Q_FUNC_INFO, "already confirmed");
if (simObject.hasValidRequestAndObjectId() && !simObject.getCallsign().isEmpty()) m_simConnectObjects[callsign].setConfirmedAdded(true);
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
{ {
CLogMessage(this).debug() << "Adding AI" << callsign.toQString() << "confirmed" << "id" << static_cast<int>(objectID) << "model" << simObject.getAircraftModelString();
}
SimConnect_AIReleaseControl(m_hSimConnect, objectID, requestID); // P3D also has SimConnect_AIReleaseControlEx;
const int requestId = m_requestId++;
HRESULT hr = SimConnect_AIReleaseControl(m_hSimConnect, objectID, static_cast<SIMCONNECT_DATA_REQUEST_ID>(requestId));
if (hr == S_OK)
{
SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeLat, 1, SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeLat, 1,
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY); SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeAlt, 1, SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeAlt, 1,
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY); SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeAtt, 1, SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeAtt, 1,
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY); SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
}
else
{
CLogMessage(this).error("Adding AI %1 failed") << callsign.toQString();
}
// optimistic approach, as the aircraft is not yet really in the SIM const bool updated = this->updateAircraftRendered(simObject.getCallsign(), true);
// its generation has been just requested if (updated)
this->updateAircraftRendered(simObject.getCallsign(), true); {
emit aircraftRenderingChanged(simObject.getAircraft()); emit aircraftRenderingChanged(simObject.getAircraft());
ok = true; }
return true;
}
bool CSimulatorFsx::simulatorReportedObjectRemoved(DWORD objectID)
{
const CSimConnectObject simObject = this->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");
bool ok = false;
if (simObject.isPendingRemoved())
{
// good case, we can remove object
}
else
{
// object was removed but not requested by us
CLogMessage(this).warning("Removed %1 from simulator, but was not initiated by us: %1 '%2' object id %3") << callsign.toQString() << simObject.getAircraftModelString() << static_cast<int>(objectID);
}
// in all cases we remove
const int c = m_simConnectObjects.remove(callsign);
m_pendingAircraftToAdd.removeByCallsign(callsign);
ok = c > 0;
CLogMessage(this).info("FSX: Removed aircraft '%1'") << simObject.getCallsign().toQString();
const bool updated = this->updateAircraftRendered(simObject.getCallsign(), false);
if (updated)
{
emit aircraftRenderingChanged(simObject.getAircraft());
}
// models we have to add again after removing
if (m_aircraftToAddAgainWhenRemoved.containsCallsign(callsign))
{
const CSimulatedAircraft aircraftAddAgain = m_aircraftToAddAgainWhenRemoved.findFirstByCallsign(callsign);
QTimer::singleShot(1000, this, [ = ] { this->physicallyAddRemoteAircraft(aircraftAddAgain); });
} }
return ok; return ok;
} }
bool CSimulatorFsx::setSimConnectObjectID(DWORD requestID, DWORD objectID) bool CSimulatorFsx::setSimConnectObjectId(DWORD requestID, DWORD objectID)
{ {
// First check, if this request id belongs to us return this->m_simConnectObjects.setSimConnectObjectId(static_cast<int>(requestID), static_cast<int>(objectID));
const int requestIntId = static_cast<int>(requestID);
auto it = std::find_if(m_simConnectObjects.begin(), m_simConnectObjects.end(), [requestIntId](const CSimConnectObject & obj) { return obj.getRequestId() == requestIntId; });
if (it == m_simConnectObjects.end()) { return false; }
// belongs to us
it->setObjectId(static_cast<int>(objectID));
return true;
}
CCallsign CSimulatorFsx::getCallsignForObjectId(DWORD objectID) const
{
return getSimObjectForObjectId(objectID).getCallsign();
}
CSimConnectObject CSimulatorFsx::getSimObjectForObjectId(DWORD objectID) const
{
const int objectIntId = static_cast<int>(objectID);
for (const CSimConnectObject &simObject : m_simConnectObjects.values())
{
if (simObject.getObjectId() == objectIntId)
{
return simObject;
}
}
return CSimConnectObject();
} }
void CSimulatorFsx::timerEvent(QTimerEvent *event) void CSimulatorFsx::timerEvent(QTimerEvent *event)
@@ -571,7 +605,7 @@ namespace BlackSimPlugin
if (m_useFsuipc && m_fsuipc) if (m_useFsuipc && m_fsuipc)
{ {
CSimulatedAircraft fsuipcAircraft(getOwnAircraft()); CSimulatedAircraft fsuipcAircraft(getOwnAircraft());
//! \todo split in high / low frequency reads //! \fixme split in high / low frequency reads
bool ok = m_fsuipc->read(fsuipcAircraft, true, true, true); bool ok = m_fsuipc->read(fsuipcAircraft, true, true, true);
if (ok) if (ok)
{ {
@@ -584,34 +618,58 @@ namespace BlackSimPlugin
bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CCallsign &callsign) bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CCallsign &callsign)
{ {
// only remove from sim // only remove from sim
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "wrong thred"); Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "wrong thread");
if (!m_simConnectObjects.contains(callsign)) { return false; } if (callsign.isEmpty()) { return false; } // can happen if an object is not an aircraft
this->physicallyRemoveRemoteAircraft(m_simConnectObjects.value(callsign));
if (m_pendingAircraftToAdd.removeByCallsign(callsign) > 0) { return true; } // was in queue to be added
if (!m_simConnectObjects.contains(callsign)) { return false; } // already fully removed or not yet added
CSimConnectObject &simObject = m_simConnectObjects[callsign];
if (simObject.isPendingRemoved()) { return true; }
if (simObject.isPendingAdded())
{
// problem: we try to delete an aircraft just requested to be added
return false; //! \todo improve
}
simObject.setPendingRemoved(true);
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
{
CLogMessage(this).debug() << "physicallyRemoveRemoteAircraft" << callsign.toQString();
}
// call in SIM
SimConnect_AIRemoveObject(m_hSimConnect, static_cast<SIMCONNECT_OBJECT_ID>(simObject.getObjectId()), static_cast<SIMCONNECT_DATA_REQUEST_ID>(m_requestId++));
// mark in provider
bool updated = updateAircraftRendered(callsign, false);
if (updated)
{
CSimulatedAircraft aircraft(simObject.getAircraft());
aircraft.setRendered(false);
emit aircraftRenderingChanged(aircraft);
}
// cleanup function, actually this should not be needed
QTimer::singleShot(100, this, &CSimulatorFsx::ps_physicallyRemoveAircraftNotInProvider);
// bye
return true; return true;
} }
int CSimulatorFsx::physicallyRemoveAllRemoteAircraft() int CSimulatorFsx::physicallyRemoveAllRemoteAircraft()
{ {
if (m_simConnectObjects.isEmpty()) { return 0; } if (m_simConnectObjects.isEmpty()) { return 0; }
QList<CCallsign> callsigns(m_simConnectObjects.keys()); const QList<CCallsign> callsigns(m_simConnectObjects.keys());
int r = 0; int r = 0;
for (const CCallsign &cs : callsigns) for (const CCallsign &cs : callsigns)
{ {
if (physicallyRemoveRemoteAircraft(cs)) { r++; } if (physicallyRemoveRemoteAircraft(cs)) { r++; }
} }
clearAllAircraft();
return r; return r;
} }
bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CSimConnectObject &simObject)
{
CCallsign callsign(simObject.getCallsign());
m_simConnectObjects.remove(callsign);
SimConnect_AIRemoveObject(m_hSimConnect, static_cast<SIMCONNECT_OBJECT_ID>(simObject.getObjectId()), static_cast<SIMCONNECT_DATA_REQUEST_ID>(simObject.getRequestId()));
updateAircraftRendered(callsign, false);
CLogMessage(this).info("FSX: Removed aircraft '%1'") << simObject.getCallsign().toQString();
return true;
}
HRESULT CSimulatorFsx::initEvents() HRESULT CSimulatorFsx::initEvents()
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
@@ -706,25 +764,29 @@ namespace BlackSimPlugin
// values used for position and parts // values used for position and parts
bool isOnGround = false; bool isOnGround = false;
qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch(); const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch();
CCallsignSet aircraftWithParts(this->remoteAircraftSupportingParts()); // optimization, fetch all parts supporting aircraft in one step (one lock) const CCallsignSet aircraftWithParts(this->remoteAircraftSupportingParts()); // optimization, fetch all parts supporting aircraft in one step (one lock)
const QList<CSimConnectObject> simObjects(m_simConnectObjects.values()); const QList<CSimConnectObject> simObjects(m_simConnectObjects.values());
for (const CSimConnectObject &simObj : simObjects) for (const CSimConnectObject &simObj : simObjects)
{ {
if (simObj.getObjectId() < 1) { continue; } // happending if aircraft is not yet added to SIM or to be deleted
if (simObj.isPendingAdded()) { continue; }
if (simObj.isPendingRemoved()) { continue; }
const CCallsign callsign(simObj.getCallsign()); const CCallsign callsign(simObj.getCallsign());
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign"); Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign");
Q_ASSERT_X(simObj.hasValidRequestAndObjectId(), Q_FUNC_INFO, "Missing ids");
IInterpolator::InterpolationStatus interpolatorStatus; IInterpolator::InterpolationStatus interpolatorStatus;
CAircraftSituation interpolatedSituation = this->m_interpolator->getInterpolatedSituation(callsign, currentTimestamp, simObj.isVtol(), interpolatorStatus); const CAircraftSituation interpolatedSituation = this->m_interpolator->getInterpolatedSituation(callsign, currentTimestamp, simObj.isVtol(), interpolatorStatus);
// having the onGround flag in parts forces me to obtain parts here // having the onGround flag in parts forces me to obtain parts here
// which is not the smartest thing regarding performance // which is not the smartest thing regarding performance
IInterpolator::PartsStatus partsStatus; IInterpolator::PartsStatus partsStatus;
partsStatus.supportsParts = aircraftWithParts.contains(callsign); partsStatus.setSupportsParts(aircraftWithParts.contains(callsign));
CAircraftPartsList parts; CAircraftPartsList parts;
if (partsStatus.supportsParts) if (partsStatus.allTrue())
{ {
parts = this->m_interpolator->getPartsBeforeTime(callsign, currentTimestamp, partsStatus); parts = this->m_interpolator->getPartsBeforeTime(callsign, currentTimestamp, partsStatus);
} }
@@ -732,13 +794,12 @@ namespace BlackSimPlugin
if (interpolatorStatus.allTrue()) if (interpolatorStatus.allTrue())
{ {
// update situation // update situation
SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxInitPosition(interpolatedSituation); SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxPosition(interpolatedSituation);
//! \todo The onGround in parts is nuts, as already mentioned in the discussion //! \fixme The onGround in parts is no ideal, as already mentioned in the discussion
// Currently ignored here, only guessing which is faster as aircraft without parts can just be
// a) I am forced to read parts even if i just want to update position // a) I am forced to read parts even if i just want to update position
// b) Unlike the other values it is not a fire and forget value, as I need it again in the next cycle // b) Unlike the other values it is not a fire and forget value, as I need it again in the next cycle
if (partsStatus.supportsParts && !parts.isEmpty()) if (partsStatus.isSupportingParts() && !parts.isEmpty())
{ {
// we have parts, and use the closest ground // we have parts, and use the closest ground
isOnGround = parts.front().isOnGround(); isOnGround = parts.front().isOnGround();
@@ -753,11 +814,14 @@ namespace BlackSimPlugin
hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPosition, hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPosition,
static_cast<SIMCONNECT_OBJECT_ID>(simObj.getObjectId()), 0, 0, static_cast<SIMCONNECT_OBJECT_ID>(simObj.getObjectId()), 0, 0,
sizeof(SIMCONNECT_DATA_INITPOSITION), &position); sizeof(SIMCONNECT_DATA_INITPOSITION), &position);
if (hr != S_OK) { CLogMessage(this).warning("Failed so set position on SimObject '%1' callsign: '%2'") << simObj.getObjectId() << callsign; } if (hr != S_OK)
{
CLogMessage(this).warning("Failed so set position on SimObject '%1' callsign: '%2'") << simObj.getObjectId() << callsign;
}
} // interpolation data } // interpolation data
if (interpolatorStatus.interpolationSucceeded) if (interpolatorStatus.didInterpolationSucceed())
{ {
// aircraft parts // aircraft parts
// inside "interpolator if", as no parts can be sent without position // inside "interpolator if", as no parts can be sent without position
@@ -765,7 +829,7 @@ namespace BlackSimPlugin
} }
} // all callsigns } // all callsigns
qint64 dt = QDateTime::currentMSecsSinceEpoch() - currentTimestamp; const qint64 dt = QDateTime::currentMSecsSinceEpoch() - currentTimestamp;
m_statsUpdateAircraftTimeTotalMs += dt; m_statsUpdateAircraftTimeTotalMs += dt;
m_statsUpdateAircraftCountMs++; m_statsUpdateAircraftCountMs++;
m_statsUpdateAircraftTimeAvgMs = m_statsUpdateAircraftTimeTotalMs / m_statsUpdateAircraftCountMs; m_statsUpdateAircraftTimeAvgMs = m_statsUpdateAircraftTimeTotalMs / m_statsUpdateAircraftCountMs;
@@ -773,9 +837,11 @@ namespace BlackSimPlugin
bool CSimulatorFsx::updateRemoteAircraftParts(const CSimConnectObject &simObj, const CAircraftPartsList &parts, IInterpolator::PartsStatus partsStatus, const CAircraftSituation &interpolatedSituation, bool isOnGround) const bool CSimulatorFsx::updateRemoteAircraftParts(const CSimConnectObject &simObj, const CAircraftPartsList &parts, IInterpolator::PartsStatus partsStatus, const CAircraftSituation &interpolatedSituation, bool isOnGround) const
{ {
if (!simObj.hasValidRequestAndObjectId()) { return false; }
// set parts // set parts
DataDefinitionRemoteAircraftParts ddRemoteAircraftParts; DataDefinitionRemoteAircraftParts ddRemoteAircraftParts;
if (partsStatus.supportsParts) if (partsStatus.isSupportingParts())
{ {
// parts is supported, but do we need to update? // parts is supported, but do we need to update?
if (parts.isEmpty()) { return false; } if (parts.isEmpty()) { return false; }
@@ -928,6 +994,47 @@ namespace BlackSimPlugin
} }
} }
void CSimulatorFsx::reset()
{
if (m_simconnectTimerId >= 0) { killTimer(m_simconnectTimerId); }
m_simConnected = false;
m_simSimulating = false;
m_simconnectTimerId = -1;
CSimulatorFsCommon::reset();
}
void CSimulatorFsx::clearAllAircraft()
{
m_simConnectObjects.clear();
CSimulatorFsCommon::clearAllAircraft();
}
QString CSimulatorFsx::fsxPositionToString(const SIMCONNECT_DATA_INITPOSITION &position)
{
const QString positionStr("Lat: %1 lng: %2 alt: %3ft pitch: %4 bank: %5 hdg: %6 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 CSimulatorFsx::getCallsignsMissingInProvider() const
{
CCallsignSet simObjectCallsigns(m_simConnectObjects.keys());
CCallsignSet providerCallsigns(this->getAircraftInRangeCallsigns());
return simObjectCallsigns.difference(providerCallsigns);
}
CCallsignSet CSimulatorFsx::ps_physicallyRemoveAircraftNotInProvider()
{
const CCallsignSet toBeRemoved(getCallsignsMissingInProvider());
if (toBeRemoved.isEmpty()) { return toBeRemoved; }
for (const CCallsign &callsign : toBeRemoved)
{
physicallyRemoveRemoteAircraft(callsign);
}
return toBeRemoved;
}
CSimulatorFsxListener::CSimulatorFsxListener(const CSimulatorPluginInfo &info) : CSimulatorFsxListener::CSimulatorFsxListener(const CSimulatorPluginInfo &info) :
ISimulatorListener(info), ISimulatorListener(info),
m_timer(new QTimer(this)) m_timer(new QTimer(this))

View File

@@ -102,6 +102,9 @@ namespace BlackSimPlugin
virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override; virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override;
//! @} //! @}
//! Display receive exceptions?
bool stillDisplayReceiveExceptions();
//! Called when data about our own aircraft are received //! Called when data about our own aircraft are received
void updateOwnAircraftFromSimulator(DataDefinitionOwnAircraft simulatorOwnAircraft); void updateOwnAircraftFromSimulator(DataDefinitionOwnAircraft simulatorOwnAircraft);
@@ -109,17 +112,16 @@ namespace BlackSimPlugin
void updateOwnAircraftFromSimulator(DataDefinitionClientAreaSb sbDataArea); void updateOwnAircraftFromSimulator(DataDefinitionClientAreaSb sbDataArea);
//! An AI aircraft was added in the simulator //! An AI aircraft was added in the simulator
//! \remark that AI aircraft was previously request by requestID bool simulatorReportedObjectAdded(DWORD objectID);
bool aiAircraftWasAddedInSimulator(DWORD requestID, 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 //! Set ID of a SimConnect object, so far we only have an request id in the object
bool setSimConnectObjectID(DWORD requestID, DWORD objectID); bool setSimConnectObjectId(DWORD requestID, DWORD objectID);
//! Find which callsign belongs to the object id //! The simconnect related objects
BlackMisc::Aviation::CCallsign getCallsignForObjectId(DWORD objectID) const; const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; }
//! Find which callsign belongs to the object id
CSimConnectObject getSimObjectForObjectId(DWORD objectID) const;
protected: protected:
//! \copydoc BlackCore::ISimulator::isConnected() //! \copydoc BlackCore::ISimulator::isConnected()
@@ -136,6 +138,10 @@ namespace BlackSimPlugin
//! Dispatch SimConnect messages //! Dispatch SimConnect messages
void ps_dispatch(); void ps_dispatch();
//! Remove aircraft not in provider anymore
//! \remark kind of cleanup function, in an ideal this should never need to cleanup something
BlackMisc::Aviation::CCallsignSet ps_physicallyRemoveAircraftNotInProvider();
private: private:
//! Call this method to declare the simulator connected //! Call this method to declare the simulator connected
void setSimConnected(); void setSimConnected();
@@ -152,9 +158,6 @@ namespace BlackSimPlugin
//! Simulator is going down //! Simulator is going down
void onSimExit(); void onSimExit();
//! Remove a remote aircraft
bool physicallyRemoveRemoteAircraft(const CSimConnectObject &simObject);
//! Init when connected //! Init when connected
HRESULT initWhenConnected(); HRESULT initWhenConnected();
@@ -172,7 +175,7 @@ namespace BlackSimPlugin
BlackMisc::IInterpolator::PartsStatus partsStatus, const BlackMisc::Aviation::CAircraftSituation &interpolatedSituation, bool isOnGround) const; BlackMisc::IInterpolator::PartsStatus partsStatus, const BlackMisc::Aviation::CAircraftSituation &interpolatedSituation, bool isOnGround) const;
//! Format conversion //! Format conversion
SIMCONNECT_DATA_INITPOSITION aircraftSituationToFsxInitPosition(const BlackMisc::Aviation::CAircraftSituation &situation); SIMCONNECT_DATA_INITPOSITION aircraftSituationToFsxPosition(const BlackMisc::Aviation::CAircraftSituation &situation, bool guessOnGround = true);
//! Sync time with user's computer //! Sync time with user's computer
void synchronizeTime(const BlackMisc::PhysicalQuantities::CTime &zuluTimeSim, const BlackMisc::PhysicalQuantities::CTime &localTimeSim); void synchronizeTime(const BlackMisc::PhysicalQuantities::CTime &zuluTimeSim, const BlackMisc::PhysicalQuantities::CTime &localTimeSim);
@@ -183,9 +186,22 @@ namespace BlackSimPlugin
//! Reload weather settings //! Reload weather settings
void reloadWeatherSettings(); void reloadWeatherSettings();
//! Reset values when restarted
virtual void reset() override;
//! Clear all aircraft lists
virtual void clearAllAircraft() override;
//! 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
BlackMisc::Aviation::CCallsignSet getCallsignsMissingInProvider() const;
static constexpr int SkipUpdateCyclesForCockpit = 10; //!< skip x cycles before updating cockpit again 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
bool m_simConnected = false; //!< Is simulator connected? bool m_simConnected = false; //!< Is simulator connected?
bool m_simSimulating = false; //!< Simulator running? bool m_simSimulating = false; //!< Simulator running?
bool m_useSbOffsets = true; //!< with SB offsets bool m_useSbOffsets = true; //!< with SB offsets
int m_syncDeferredCounter = 0; //!< Set when synchronized, used to wait some time int m_syncDeferredCounter = 0; //!< Set when synchronized, used to wait some time
int m_simconnectTimerId = -1; //!< Timer identifier int m_simconnectTimerId = -1; //!< Timer identifier
@@ -193,10 +209,10 @@ namespace BlackSimPlugin
int m_interpolationRequest = 0; //!< current interpolation request int m_interpolationRequest = 0; //!< current interpolation request
int m_interpolationsSkipped = 0; //!< number of skipped interpolation request int m_interpolationsSkipped = 0; //!< number of skipped interpolation request
int m_requestId = 1; //!< request id int m_requestId = 1; //!< request id
int m_dispatchErrors = 0; //!< numer of dispatched failed, \sa ps_dispatch int m_dispatchErrors = 0; //!< number of dispatched failed, \sa ps_dispatch
int m_receiveExceptionCount = 0; //!< exceptions
HANDLE m_hSimConnect = nullptr; //!< Handle to SimConnect object HANDLE m_hSimConnect = nullptr; //!< Handle to SimConnect object
QHash<BlackMisc::Aviation::CCallsign, CSimConnectObject> m_simConnectObjects; CSimConnectObjects m_simConnectObjects; //!< AI objects and their object / request ids
BlackMisc::Geo::CCoordinateGeodetic m_lastWeatherPosition; //!< Own aircraft position at which weather was fetched and injected last BlackMisc::Geo::CCoordinateGeodetic m_lastWeatherPosition; //!< Own aircraft position at which weather was fetched and injected last
BlackMisc::CSetting<BlackCore::Simulator::TSelectedWeatherScenario> m_weatherScenarioSettings { this, &CSimulatorFsx::reloadWeatherSettings }; BlackMisc::CSetting<BlackCore::Simulator::TSelectedWeatherScenario> m_weatherScenarioSettings { this, &CSimulatorFsx::reloadWeatherSettings };
}; };

View File

@@ -50,6 +50,11 @@ namespace BlackSimPlugin
} }
case SIMCONNECT_RECV_ID_EXCEPTION: case SIMCONNECT_RECV_ID_EXCEPTION:
{ {
if (!simulatorFsx->stillDisplayReceiveExceptions())
{
break;
}
SIMCONNECT_RECV_EXCEPTION *exception = (SIMCONNECT_RECV_EXCEPTION *)pData; SIMCONNECT_RECV_EXCEPTION *exception = (SIMCONNECT_RECV_EXCEPTION *)pData;
QString ex; QString ex;
const int exceptionId = static_cast<int>(exception->dwException); const int exceptionId = static_cast<int>(exception->dwException);
@@ -57,17 +62,19 @@ namespace BlackSimPlugin
const int index = static_cast<int>(exception->dwIndex); const int index = static_cast<int>(exception->dwIndex);
const int data = static_cast<int>(cbData); const int data = static_cast<int>(cbData);
ex.sprintf("Exception=%d SendID=%d Index=%d cbData=%d", exceptionId, sendId, index, data); ex.sprintf("Exception=%d SendID=%d Index=%d cbData=%d", exceptionId, sendId, index, data);
if (exceptionId == SIMCONNECT_EXCEPTION_OPERATION_INVALID_FOR_OBJECT_TYPE)
switch (exceptionId)
{ {
// means we have problems with an AI aircraft case SIMCONNECT_EXCEPTION_OPERATION_INVALID_FOR_OBJECT_TYPE:
//! \todo find out how to obtain the id here so I can get callsign case SIMCONNECT_EXCEPTION_UNRECOGNIZED_ID:
CCallsign cs = simulatorFsx->getCallsignForObjectId(data);
if (!cs.isEmpty())
{ {
ex += " callsign: "; //! \fixme do not know how to obtain the object id which failed. Can I get it?
ex += cs.toQString();
} }
break;
default:
break;
} }
CLogMessage(simulatorFsx).error("Caught FSX simConnect exception: %1 %2") CLogMessage(simulatorFsx).error("Caught FSX simConnect exception: %1 %2")
<< CSimConnectUtilities::simConnectExceptionToString((SIMCONNECT_EXCEPTION)exception->dwException) << CSimConnectUtilities::simConnectExceptionToString((SIMCONNECT_EXCEPTION)exception->dwException)
<< ex; << ex;
@@ -114,11 +121,24 @@ namespace BlackSimPlugin
case SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE: case SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE:
{ {
SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *event = static_cast<SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *>(pData); SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *event = static_cast<SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *>(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;
}
// such an object is not necessarily one of ours
// for instance, I always see object 5 when I start the simulator
if (!simulatorFsx->getSimConnectObjects().isKnownSimObjectId(objectID)) break;
switch (event->uEventID) switch (event->uEventID)
{ {
case SystemEventObjectAdded: case SystemEventObjectAdded:
// added in SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID
// adding here cause trouble
break; break;
case SystemEventObjectRemoved: case SystemEventObjectRemoved:
simulatorFsx->simulatorReportedObjectRemoved(objectID);
break; break;
default: default:
break; break;
@@ -131,6 +151,7 @@ namespace BlackSimPlugin
switch (event->uEventID) switch (event->uEventID)
{ {
case SystemEventFrame: case SystemEventFrame:
// doing interpolation
simulatorFsx->onSimFrame(); simulatorFsx->onSimFrame();
break; break;
default: default:
@@ -143,13 +164,16 @@ namespace BlackSimPlugin
SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast<SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *>(pData); SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast<SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *>(pData);
const DWORD requestID = event->dwRequestID; const DWORD requestID = event->dwRequestID;
const DWORD objectID = event->dwObjectID; const DWORD objectID = event->dwObjectID;
const bool success = simulatorFsx->aiAircraftWasAddedInSimulator(requestID, objectID); bool success = simulatorFsx->setSimConnectObjectId(requestID, objectID);
if (!success) { break; } // not an request ID of ours
success = simulatorFsx->simulatorReportedObjectAdded(objectID);
if (!success) if (!success)
{ {
CLogMessage(simulatorFsx).warning("Cannot find CSimConnectObject for request %1") << requestID; const CSimulatedAircraft remoteAircraft(simulatorFsx->getSimConnectObjects().getSimObjectForObjectId(objectID).getAircraft());
const CSimulatedAircraft remoteAircraft(simulatorFsx->getSimObjectForObjectId(objectID).getAircraft()); const CStatusMessage msg = CStatusMessage(simulatorFsx).error("Cannot add object %1") << objectID;
const QString msg("Object id for request " + QString::number(requestID) + " not avialable"); CLogMessage::preformatted(msg);
emit simulatorFsx->physicallyAddingRemoteModelFailed(remoteAircraft, CStatusMessage(simulatorFsx, CStatusMessage::SeverityError, msg)); emit simulatorFsx->physicallyAddingRemoteModelFailed(remoteAircraft, msg);
} }
break; break;
} }