mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-07 11:05:33 +08:00
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:
@@ -106,7 +106,8 @@ namespace BlackSimPlugin
|
||||
{
|
||||
connect(lobbyClient.data(), &CLobbyClient::disconnected, this, std::bind(&CSimulatorFs9::simulatorStatusChanged, this, 0));
|
||||
this->m_interpolator = new BlackMisc::CInterpolatorLinear(remoteAircraftProvider, this);
|
||||
m_defaultModel = {
|
||||
m_defaultModel =
|
||||
{
|
||||
"Boeing 737-400",
|
||||
CAircraftModel::TypeModelMatchingDefaultModel,
|
||||
"B737-400 default model",
|
||||
@@ -170,10 +171,13 @@ namespace BlackSimPlugin
|
||||
client->start();
|
||||
|
||||
m_hashFs9Clients.insert(callsign, client);
|
||||
updateAircraftRendered(callsign, rendered);
|
||||
bool updated = updateAircraftRendered(callsign, rendered);
|
||||
CSimulatedAircraft remoteAircraftCopy(newRemoteAircraft);
|
||||
remoteAircraftCopy.setRendered(rendered);
|
||||
emit aircraftRenderingChanged(remoteAircraftCopy);
|
||||
if (updated)
|
||||
{
|
||||
emit aircraftRenderingChanged(remoteAircraftCopy);
|
||||
}
|
||||
CLogMessage(this).info("FS9: Added aircraft %1") << callsign.toQString();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace BlackSimPlugin
|
||||
{
|
||||
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 events http://msdn.microsoft.com/en-us/library/cc526980.aspx
|
||||
struct DataDefinitionOwnAircraft
|
||||
@@ -40,12 +40,12 @@ namespace BlackSimPlugin
|
||||
double velocity; //!< Ground velocity
|
||||
double simOnGround; //!< Is aircraft on ground?
|
||||
|
||||
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 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 transponderCode; //!< Transponder Code
|
||||
double com1ActiveMHz; //!< COM1 active frequency
|
||||
@@ -73,22 +73,22 @@ namespace BlackSimPlugin
|
||||
//! Data struct of remote aircraft parts
|
||||
struct DataDefinitionRemoteAircraftParts
|
||||
{
|
||||
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 flapsLeadingEdgeLeftPercent; //!< Leading edge left in percent
|
||||
double flapsLeadingEdgeRightPercent; //!< Leading edge right in percent
|
||||
double flapsTrailingEdgeLeftPercent; //!< Trailing edge left in percent
|
||||
double flapsTrailingEdgeRightPercent; //!< Trailing edge right in percent
|
||||
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 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 flapsLeadingEdgeLeftPercent; //!< Leading edge left in percent
|
||||
double flapsLeadingEdgeRightPercent; //!< Leading edge right in percent
|
||||
double flapsTrailingEdgeLeftPercent; //!< Trailing edge left in percent
|
||||
double flapsTrailingEdgeRightPercent; //!< Trailing edge right in percent
|
||||
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
|
||||
};
|
||||
|
||||
//! Data struct simulator environment
|
||||
@@ -134,7 +134,6 @@ namespace BlackSimPlugin
|
||||
class CSimConnectDefinitions
|
||||
{
|
||||
public:
|
||||
|
||||
//! SimConnect definiton IDs
|
||||
enum DataDefiniton
|
||||
{
|
||||
@@ -168,7 +167,6 @@ namespace BlackSimPlugin
|
||||
static QString getLogCategory() { return "swift.fsx.simconnect"; }
|
||||
|
||||
private:
|
||||
|
||||
//! Initialize data definition for our own aircraft
|
||||
static HRESULT initOwnAircraft(const HANDLE hSimConnect);
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@ namespace BlackSimPlugin
|
||||
//! Simulated aircraft (as added)
|
||||
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
|
||||
void setRequestId(int id) { m_requestId = id; }
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "blackmisc/aviation/airportlist.h"
|
||||
#include "blackmisc/logmessage.h"
|
||||
#include "blackmisc/threadutils.h"
|
||||
#include "blackmisc/verify.h"
|
||||
#include "blackmisc/simulation/fscommon/fscommonutil.h"
|
||||
|
||||
#include <QTimer>
|
||||
@@ -81,12 +82,10 @@ namespace BlackSimPlugin
|
||||
bool CSimulatorFsx::connectTo()
|
||||
{
|
||||
if (this->isConnected()) { return true; }
|
||||
this->reset();
|
||||
if (FAILED(SimConnect_Open(&m_hSimConnect, sApp->swiftVersionChar(), nullptr, 0, 0, 0)))
|
||||
{
|
||||
// reset state as expected for unconnected
|
||||
if (m_simconnectTimerId >= 0) { killTimer(m_simconnectTimerId); }
|
||||
m_simConnected = false;
|
||||
m_simSimulating = false;
|
||||
return false;
|
||||
}
|
||||
if (m_useFsuipc) { this->m_fsuipc->connect(); } // FSUIPC too
|
||||
@@ -102,25 +101,14 @@ namespace BlackSimPlugin
|
||||
bool CSimulatorFsx::disconnectFrom()
|
||||
{
|
||||
if (!m_simConnected) { return true; }
|
||||
|
||||
// stop mapper init
|
||||
//! \todo mapper shutdown in FSX, review keep it?
|
||||
// mapperInstance()->gracefulShutdown();
|
||||
|
||||
if (m_simconnectTimerId)
|
||||
{
|
||||
killTimer(m_simconnectTimerId);
|
||||
}
|
||||
|
||||
if (m_simconnectTimerId) { killTimer(m_simconnectTimerId); }
|
||||
if (m_hSimConnect)
|
||||
{
|
||||
SimConnect_Close(m_hSimConnect);
|
||||
m_hSimConnect = nullptr;
|
||||
}
|
||||
|
||||
m_simConnected = false;
|
||||
m_simSimulating = false;
|
||||
m_simconnectTimerId = -1;
|
||||
reset();
|
||||
|
||||
// emit status and disconnect FSUIPC
|
||||
CSimulatorFsCommon::disconnectFrom();
|
||||
@@ -136,8 +124,26 @@ namespace BlackSimPlugin
|
||||
Q_ASSERT_X(newRemoteAircraft.hasModelString(), Q_FUNC_INFO, "missing model string");
|
||||
if (callsign.isEmpty()) { return false; }
|
||||
|
||||
const bool aircraftAlreadyExistsInSim = this->m_simConnectObjects.contains(callsign);
|
||||
if (aircraftAlreadyExistsInSim)
|
||||
// check if we have to do something
|
||||
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];
|
||||
if (simObj.isPendingAdded())
|
||||
@@ -164,11 +170,17 @@ namespace BlackSimPlugin
|
||||
// initial position
|
||||
setInitialAircraftSituation(addedAircraft); // set interpolated data/parts if available
|
||||
|
||||
SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxInitPosition(addedAircraft.getSituation());
|
||||
const QByteArray m = aircraftModel.getModelString().toLocal8Bit();
|
||||
const int requestId = m_requestId++;
|
||||
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));
|
||||
if (hr != S_OK)
|
||||
{
|
||||
@@ -275,22 +287,13 @@ namespace BlackSimPlugin
|
||||
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;
|
||||
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;
|
||||
}
|
||||
HRESULT hr = SimConnect_Text(
|
||||
m_hSimConnect, type, 7.5, EventTextMessage, static_cast<DWORD>(m.size()),
|
||||
m.data()
|
||||
);
|
||||
HRESULT hr = SimConnect_Text(m_hSimConnect, type, 7.5, EventTextMessage,
|
||||
static_cast<DWORD>(m.size()), m.data());
|
||||
Q_UNUSED(hr);
|
||||
}
|
||||
|
||||
@@ -312,6 +315,12 @@ namespace BlackSimPlugin
|
||||
return CCallsignSet(this->m_simConnectObjects.keys());
|
||||
}
|
||||
|
||||
bool CSimulatorFsx::stillDisplayReceiveExceptions()
|
||||
{
|
||||
m_receiveExceptionCount++;
|
||||
return m_receiveExceptionCount < IgnoreReceiveExceptions;
|
||||
}
|
||||
|
||||
void CSimulatorFsx::setSimConnected()
|
||||
{
|
||||
m_simConnected = true;
|
||||
@@ -404,8 +413,7 @@ namespace BlackSimPlugin
|
||||
simulatorOwnAircraft.lightLogo);
|
||||
|
||||
QList<bool> helperList {simulatorOwnAircraft.engine1Combustion != 0, simulatorOwnAircraft.engine2Combustion != 0,
|
||||
simulatorOwnAircraft.engine3Combustion != 0, simulatorOwnAircraft.engine4Combustion != 0
|
||||
};
|
||||
simulatorOwnAircraft.engine3Combustion != 0, simulatorOwnAircraft.engine4Combustion != 0 };
|
||||
|
||||
CAircraftEngineList engines;
|
||||
for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index)
|
||||
@@ -436,16 +444,16 @@ namespace BlackSimPlugin
|
||||
// updates
|
||||
com1.setFrequencyActive(CFrequency(simulatorOwnAircraft.com1ActiveMHz, CFrequencyUnit::MHz()));
|
||||
com1.setFrequencyStandby(CFrequency(simulatorOwnAircraft.com1StandbyMHz, CFrequencyUnit::MHz()));
|
||||
bool changedCom1 = myAircraft.getCom1System() != com1;
|
||||
const bool changedCom1 = myAircraft.getCom1System() != com1;
|
||||
this->m_simCom1 = com1;
|
||||
|
||||
com2.setFrequencyActive(CFrequency(simulatorOwnAircraft.com2ActiveMHz, CFrequencyUnit::MHz()));
|
||||
com2.setFrequencyStandby(CFrequency(simulatorOwnAircraft.com2StandbyMHz, CFrequencyUnit::MHz()));
|
||||
bool changedCom2 = myAircraft.getCom2System() != com2;
|
||||
const bool changedCom2 = myAircraft.getCom2System() != com2;
|
||||
this->m_simCom2 = com2;
|
||||
|
||||
transponder.setTransponderCode(simulatorOwnAircraft.transponderCode);
|
||||
bool changedXpr = (myAircraft.getTransponderCode() != transponder.getTransponderCode());
|
||||
const bool changedXpr = (myAircraft.getTransponderCode() != transponder.getTransponderCode());
|
||||
|
||||
if (changedCom1 || changedCom2 || changedXpr)
|
||||
{
|
||||
@@ -486,60 +494,86 @@ namespace BlackSimPlugin
|
||||
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->getSimObjectForObjectId(objectID);
|
||||
const CSimConnectObject simObject = this->m_simConnectObjects.getSimObjectForObjectId(objectID);
|
||||
const CCallsign callsign(simObject.getCallsign());
|
||||
if (!simObject.hasValidRequestAndObjectId() || callsign.isEmpty()) { return false; }
|
||||
|
||||
bool ok = false;
|
||||
if (simObject.hasValidRequestAndObjectId() && !simObject.getCallsign().isEmpty())
|
||||
Q_ASSERT_X(simObject.isPendingAdded(), Q_FUNC_INFO, "already confirmed");
|
||||
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_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeAlt, 1,
|
||||
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
SimConnect_TransmitClientEvent(m_hSimConnect, objectID, EventFreezeAtt, 1,
|
||||
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
|
||||
// its generation has been just requested
|
||||
this->updateAircraftRendered(simObject.getCallsign(), true);
|
||||
const bool updated = this->updateAircraftRendered(simObject.getCallsign(), true);
|
||||
if (updated)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool CSimulatorFsx::setSimConnectObjectID(DWORD requestID, DWORD objectID)
|
||||
bool CSimulatorFsx::setSimConnectObjectId(DWORD requestID, DWORD objectID)
|
||||
{
|
||||
// First check, if this request id belongs to us
|
||||
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();
|
||||
return this->m_simConnectObjects.setSimConnectObjectId(static_cast<int>(requestID), static_cast<int>(objectID));
|
||||
}
|
||||
|
||||
void CSimulatorFsx::timerEvent(QTimerEvent *event)
|
||||
@@ -571,7 +605,7 @@ namespace BlackSimPlugin
|
||||
if (m_useFsuipc && m_fsuipc)
|
||||
{
|
||||
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);
|
||||
if (ok)
|
||||
{
|
||||
@@ -584,34 +618,58 @@ namespace BlackSimPlugin
|
||||
bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CCallsign &callsign)
|
||||
{
|
||||
// only remove from sim
|
||||
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "wrong thred");
|
||||
if (!m_simConnectObjects.contains(callsign)) { return false; }
|
||||
this->physicallyRemoveRemoteAircraft(m_simConnectObjects.value(callsign));
|
||||
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "wrong thread");
|
||||
if (callsign.isEmpty()) { return false; } // can happen if an object is not an aircraft
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int CSimulatorFsx::physicallyRemoveAllRemoteAircraft()
|
||||
{
|
||||
if (m_simConnectObjects.isEmpty()) { return 0; }
|
||||
QList<CCallsign> callsigns(m_simConnectObjects.keys());
|
||||
const QList<CCallsign> callsigns(m_simConnectObjects.keys());
|
||||
int r = 0;
|
||||
for (const CCallsign &cs : callsigns)
|
||||
{
|
||||
if (physicallyRemoveRemoteAircraft(cs)) { r++; }
|
||||
}
|
||||
clearAllAircraft();
|
||||
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 hr = S_OK;
|
||||
@@ -706,25 +764,29 @@ namespace BlackSimPlugin
|
||||
|
||||
// values used for position and parts
|
||||
bool isOnGround = false;
|
||||
qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||
CCallsignSet aircraftWithParts(this->remoteAircraftSupportingParts()); // optimization, fetch all parts supporting aircraft in one step (one lock)
|
||||
const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||
const CCallsignSet aircraftWithParts(this->remoteAircraftSupportingParts()); // optimization, fetch all parts supporting aircraft in one step (one lock)
|
||||
|
||||
const QList<CSimConnectObject> simObjects(m_simConnectObjects.values());
|
||||
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());
|
||||
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign");
|
||||
Q_ASSERT_X(simObj.hasValidRequestAndObjectId(), Q_FUNC_INFO, "Missing ids");
|
||||
|
||||
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
|
||||
// which is not the smartest thing regarding performance
|
||||
IInterpolator::PartsStatus partsStatus;
|
||||
partsStatus.supportsParts = aircraftWithParts.contains(callsign);
|
||||
partsStatus.setSupportsParts(aircraftWithParts.contains(callsign));
|
||||
CAircraftPartsList parts;
|
||||
if (partsStatus.supportsParts)
|
||||
if (partsStatus.allTrue())
|
||||
{
|
||||
parts = this->m_interpolator->getPartsBeforeTime(callsign, currentTimestamp, partsStatus);
|
||||
}
|
||||
@@ -732,13 +794,12 @@ namespace BlackSimPlugin
|
||||
if (interpolatorStatus.allTrue())
|
||||
{
|
||||
// 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
|
||||
// Currently ignored here, only guessing which is faster as aircraft without parts can just be
|
||||
//! \fixme The onGround in parts is no ideal, as already mentioned in the discussion
|
||||
// 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
|
||||
if (partsStatus.supportsParts && !parts.isEmpty())
|
||||
if (partsStatus.isSupportingParts() && !parts.isEmpty())
|
||||
{
|
||||
// we have parts, and use the closest ground
|
||||
isOnGround = parts.front().isOnGround();
|
||||
@@ -753,11 +814,14 @@ namespace BlackSimPlugin
|
||||
hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPosition,
|
||||
static_cast<SIMCONNECT_OBJECT_ID>(simObj.getObjectId()), 0, 0,
|
||||
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
|
||||
|
||||
if (interpolatorStatus.interpolationSucceeded)
|
||||
if (interpolatorStatus.didInterpolationSucceed())
|
||||
{
|
||||
// aircraft parts
|
||||
// inside "interpolator if", as no parts can be sent without position
|
||||
@@ -765,7 +829,7 @@ namespace BlackSimPlugin
|
||||
}
|
||||
|
||||
} // all callsigns
|
||||
qint64 dt = QDateTime::currentMSecsSinceEpoch() - currentTimestamp;
|
||||
const qint64 dt = QDateTime::currentMSecsSinceEpoch() - currentTimestamp;
|
||||
m_statsUpdateAircraftTimeTotalMs += dt;
|
||||
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
|
||||
{
|
||||
if (!simObj.hasValidRequestAndObjectId()) { return false; }
|
||||
|
||||
// set parts
|
||||
DataDefinitionRemoteAircraftParts ddRemoteAircraftParts;
|
||||
if (partsStatus.supportsParts)
|
||||
if (partsStatus.isSupportingParts())
|
||||
{
|
||||
// parts is supported, but do we need to update?
|
||||
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) :
|
||||
ISimulatorListener(info),
|
||||
m_timer(new QTimer(this))
|
||||
|
||||
@@ -102,6 +102,9 @@ namespace BlackSimPlugin
|
||||
virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override;
|
||||
//! @}
|
||||
|
||||
//! Display receive exceptions?
|
||||
bool stillDisplayReceiveExceptions();
|
||||
|
||||
//! Called when data about our own aircraft are received
|
||||
void updateOwnAircraftFromSimulator(DataDefinitionOwnAircraft simulatorOwnAircraft);
|
||||
|
||||
@@ -109,17 +112,16 @@ namespace BlackSimPlugin
|
||||
void updateOwnAircraftFromSimulator(DataDefinitionClientAreaSb sbDataArea);
|
||||
|
||||
//! An AI aircraft was added in the simulator
|
||||
//! \remark that AI aircraft was previously request by requestID
|
||||
bool aiAircraftWasAddedInSimulator(DWORD requestID, DWORD objectID);
|
||||
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);
|
||||
bool setSimConnectObjectId(DWORD requestID, DWORD objectID);
|
||||
|
||||
//! Find which callsign belongs to the object id
|
||||
BlackMisc::Aviation::CCallsign getCallsignForObjectId(DWORD objectID) const;
|
||||
|
||||
//! Find which callsign belongs to the object id
|
||||
CSimConnectObject getSimObjectForObjectId(DWORD objectID) const;
|
||||
//! The simconnect related objects
|
||||
const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; }
|
||||
|
||||
protected:
|
||||
//! \copydoc BlackCore::ISimulator::isConnected()
|
||||
@@ -136,6 +138,10 @@ namespace BlackSimPlugin
|
||||
//! Dispatch SimConnect messages
|
||||
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:
|
||||
//! Call this method to declare the simulator connected
|
||||
void setSimConnected();
|
||||
@@ -152,9 +158,6 @@ namespace BlackSimPlugin
|
||||
//! Simulator is going down
|
||||
void onSimExit();
|
||||
|
||||
//! Remove a remote aircraft
|
||||
bool physicallyRemoveRemoteAircraft(const CSimConnectObject &simObject);
|
||||
|
||||
//! Init when connected
|
||||
HRESULT initWhenConnected();
|
||||
|
||||
@@ -172,7 +175,7 @@ namespace BlackSimPlugin
|
||||
BlackMisc::IInterpolator::PartsStatus partsStatus, const BlackMisc::Aviation::CAircraftSituation &interpolatedSituation, bool isOnGround) const;
|
||||
|
||||
//! 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
|
||||
void synchronizeTime(const BlackMisc::PhysicalQuantities::CTime &zuluTimeSim, const BlackMisc::PhysicalQuantities::CTime &localTimeSim);
|
||||
@@ -183,9 +186,22 @@ namespace BlackSimPlugin
|
||||
//! Reload weather settings
|
||||
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 IgnoreReceiveExceptions = 10; //!< skip exceptions when displayed more than x times
|
||||
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
|
||||
int m_syncDeferredCounter = 0; //!< Set when synchronized, used to wait some time
|
||||
int m_simconnectTimerId = -1; //!< Timer identifier
|
||||
@@ -193,10 +209,10 @@ namespace BlackSimPlugin
|
||||
int m_interpolationRequest = 0; //!< current interpolation request
|
||||
int m_interpolationsSkipped = 0; //!< number of skipped interpolation request
|
||||
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
|
||||
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::CSetting<BlackCore::Simulator::TSelectedWeatherScenario> m_weatherScenarioSettings { this, &CSimulatorFsx::reloadWeatherSettings };
|
||||
};
|
||||
|
||||
@@ -50,6 +50,11 @@ namespace BlackSimPlugin
|
||||
}
|
||||
case SIMCONNECT_RECV_ID_EXCEPTION:
|
||||
{
|
||||
if (!simulatorFsx->stillDisplayReceiveExceptions())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
SIMCONNECT_RECV_EXCEPTION *exception = (SIMCONNECT_RECV_EXCEPTION *)pData;
|
||||
QString ex;
|
||||
const int exceptionId = static_cast<int>(exception->dwException);
|
||||
@@ -57,17 +62,19 @@ namespace BlackSimPlugin
|
||||
const int index = static_cast<int>(exception->dwIndex);
|
||||
const int data = static_cast<int>(cbData);
|
||||
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
|
||||
//! \todo find out how to obtain the id here so I can get callsign
|
||||
CCallsign cs = simulatorFsx->getCallsignForObjectId(data);
|
||||
if (!cs.isEmpty())
|
||||
case SIMCONNECT_EXCEPTION_OPERATION_INVALID_FOR_OBJECT_TYPE:
|
||||
case SIMCONNECT_EXCEPTION_UNRECOGNIZED_ID:
|
||||
{
|
||||
ex += " callsign: ";
|
||||
ex += cs.toQString();
|
||||
//! \fixme do not know how to obtain the object id which failed. Can I get it?
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CLogMessage(simulatorFsx).error("Caught FSX simConnect exception: %1 %2")
|
||||
<< CSimConnectUtilities::simConnectExceptionToString((SIMCONNECT_EXCEPTION)exception->dwException)
|
||||
<< ex;
|
||||
@@ -114,11 +121,24 @@ namespace BlackSimPlugin
|
||||
case SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE:
|
||||
{
|
||||
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)
|
||||
{
|
||||
case SystemEventObjectAdded:
|
||||
// added in SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID
|
||||
// adding here cause trouble
|
||||
break;
|
||||
case SystemEventObjectRemoved:
|
||||
simulatorFsx->simulatorReportedObjectRemoved(objectID);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -131,6 +151,7 @@ namespace BlackSimPlugin
|
||||
switch (event->uEventID)
|
||||
{
|
||||
case SystemEventFrame:
|
||||
// doing interpolation
|
||||
simulatorFsx->onSimFrame();
|
||||
break;
|
||||
default:
|
||||
@@ -143,13 +164,16 @@ namespace BlackSimPlugin
|
||||
SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast<SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *>(pData);
|
||||
const DWORD requestID = event->dwRequestID;
|
||||
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)
|
||||
{
|
||||
CLogMessage(simulatorFsx).warning("Cannot find CSimConnectObject for request %1") << requestID;
|
||||
const CSimulatedAircraft remoteAircraft(simulatorFsx->getSimObjectForObjectId(objectID).getAircraft());
|
||||
const QString msg("Object id for request " + QString::number(requestID) + " not avialable");
|
||||
emit simulatorFsx->physicallyAddingRemoteModelFailed(remoteAircraft, CStatusMessage(simulatorFsx, CStatusMessage::SeverityError, msg));
|
||||
const CSimulatedAircraft remoteAircraft(simulatorFsx->getSimConnectObjects().getSimObjectForObjectId(objectID).getAircraft());
|
||||
const CStatusMessage msg = CStatusMessage(simulatorFsx).error("Cannot add object %1") << objectID;
|
||||
CLogMessage::preformatted(msg);
|
||||
emit simulatorFsx->physicallyAddingRemoteModelFailed(remoteAircraft, msg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user