mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-31 21:15:33 +08:00
refs #840, FSX driver: get ground elevation from simulator
* fixed wrong request id * made functions private where possible * added data definitions for simobject data
This commit is contained in:
committed by
Mathew Sutcliffe
parent
be297d8ccf
commit
93a18f433c
@@ -16,7 +16,6 @@ namespace BlackSimPlugin
|
||||
{
|
||||
namespace Fsx
|
||||
{
|
||||
|
||||
CSimConnectDefinitions::CSimConnectDefinitions() { }
|
||||
|
||||
HRESULT CSimConnectDefinitions::initDataDefinitionsWhenConnected(const HANDLE hSimConnect)
|
||||
@@ -24,6 +23,7 @@ namespace BlackSimPlugin
|
||||
HRESULT hr = S_OK;
|
||||
hr += initOwnAircraft(hSimConnect);
|
||||
hr += initRemoteAircraft(hSimConnect);
|
||||
hr += initRemoteAircraftSimData(hSimConnect);
|
||||
hr += initSimulatorEnvironment(hSimConnect);
|
||||
hr += initSbDataArea(hSimConnect);
|
||||
return hr;
|
||||
@@ -32,14 +32,14 @@ namespace BlackSimPlugin
|
||||
HRESULT CSimConnectDefinitions::initOwnAircraft(const HANDLE hSimConnect)
|
||||
{
|
||||
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 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, "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 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", "Meters");
|
||||
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");
|
||||
@@ -106,7 +106,21 @@ namespace BlackSimPlugin
|
||||
{
|
||||
CLogMessage(static_cast<CSimConnectDefinitions *>(nullptr)).error("SimConnect error: initRemoteAircraftSituation %1") << hr;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CSimConnectDefinitions::initRemoteAircraftSimData(const HANDLE hSimConnect)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSimData, "PLANE LATITUDE", "degrees");
|
||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSimData, "PLANE LONGITUDE", "degrees");
|
||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSimData, "PLANE ALTITUDE", "Feet");
|
||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSimData, "GROUND ALTITUDE", "Feet");
|
||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftSimData, "STATIC CG TO GROUND", "Feet");
|
||||
if (hr != S_OK)
|
||||
{
|
||||
CLogMessage(static_cast<CSimConnectDefinitions *>(nullptr)).error("SimConnect error: initRemoteAircraftSimData %1") << hr;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
@@ -162,6 +176,5 @@ namespace BlackSimPlugin
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace BlackSimPlugin
|
||||
double pitch; //!< Pitch (deg)
|
||||
double bank; //!< Bank (deg)
|
||||
double velocity; //!< Ground velocity
|
||||
double elevation; //!< Elevation (m)
|
||||
double elevation; //!< Elevation (ft)
|
||||
double simOnGround; //!< Is aircraft on ground?
|
||||
|
||||
double lightStrobe; //!< Is strobe light on?
|
||||
@@ -92,6 +92,19 @@ namespace BlackSimPlugin
|
||||
double engine4Combustion; //!< Engine 4 combustion flag
|
||||
};
|
||||
|
||||
//! Data for AI object sent back from simulator
|
||||
struct DataDefinitionRemoteAircraftSimData
|
||||
{
|
||||
double latitude; //!< Latitude (deg)
|
||||
double longitude; //!< Longitude (deg)
|
||||
double altitude; //!< Altitude (ft)
|
||||
double elevation; //!< Elevation (ft)
|
||||
double cgToGround; //!< CG to ground (ft)
|
||||
|
||||
//! Above ground ft
|
||||
double aboveGround() const { return altitude - elevation; }
|
||||
};
|
||||
|
||||
//! Data struct simulator environment
|
||||
struct DataDefinitionSimEnvironment
|
||||
{
|
||||
@@ -142,6 +155,7 @@ namespace BlackSimPlugin
|
||||
DataOwnAircraftTitle,
|
||||
DataRemoteAircraftParts,
|
||||
DataRemoteAircraftPosition,
|
||||
DataRemoteAircraftSimData,
|
||||
DataSimEnvironment,
|
||||
DataClientAreaSb, //!< whole SB area
|
||||
DataClientAreaSbIdent, //!< ident single value
|
||||
@@ -155,7 +169,8 @@ namespace BlackSimPlugin
|
||||
RequestRemoveAircraft,
|
||||
RequestOwnAircraftTitle,
|
||||
RequestSimEnvironment,
|
||||
RequestSbData, //!< SB client area / XPDR mode
|
||||
RequestSbData, //!< SB client area / XPDR mode
|
||||
RequestEndMarker //!< free request ids can start here
|
||||
};
|
||||
|
||||
//! Constructor
|
||||
@@ -171,9 +186,12 @@ namespace BlackSimPlugin
|
||||
//! Initialize data definition for our own aircraft
|
||||
static HRESULT initOwnAircraft(const HANDLE hSimConnect);
|
||||
|
||||
//! Initialize data definition for remote aircrafts
|
||||
//! Initialize data definition for remote aircraft
|
||||
static HRESULT initRemoteAircraft(const HANDLE hSimConnect);
|
||||
|
||||
//! Initialize data for remote aircraft queried from simulator
|
||||
static HRESULT initRemoteAircraftSimData(const HANDLE hSimConnect);
|
||||
|
||||
//! Initialize data definition for Simulator environment
|
||||
static HRESULT initSimulatorEnvironment(const HANDLE hSimConnect);
|
||||
|
||||
|
||||
@@ -75,6 +75,15 @@ namespace BlackSimPlugin
|
||||
return CSimConnectObject();
|
||||
}
|
||||
|
||||
CSimConnectObject CSimConnectObjects::getSimObjectForRequestId(DWORD requestId) const
|
||||
{
|
||||
for (const CSimConnectObject &simObject : this->values())
|
||||
{
|
||||
if (simObject.getRequestId() == requestId) { return simObject; }
|
||||
}
|
||||
return CSimConnectObject();
|
||||
}
|
||||
|
||||
bool CSimConnectObjects::isKnownSimObjectId(DWORD objectId) const
|
||||
{
|
||||
const CSimConnectObject simObject(getSimObjectForObjectId(objectId));
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
#include "simconnect/SimConnect.h"
|
||||
#include <QSharedPointer>
|
||||
|
||||
namespace BlackMisc { class IInterpolator; }
|
||||
|
||||
namespace BlackMisc { namespace Simulation { class IInterpolator; } }
|
||||
namespace BlackSimPlugin
|
||||
{
|
||||
namespace Fsx
|
||||
@@ -44,6 +43,12 @@ namespace BlackSimPlugin
|
||||
//! Simulated aircraft model string
|
||||
const QString &getAircraftModelString() const { return m_aircraft.getModelString(); }
|
||||
|
||||
//! 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) { m_requestId = id; m_validRequestId = true; }
|
||||
|
||||
@@ -87,6 +92,7 @@ namespace BlackSimPlugin
|
||||
BlackMisc::Simulation::CSimulatedAircraft m_aircraft;
|
||||
DWORD m_requestId = 0;
|
||||
DWORD m_objectId = 0;
|
||||
SIMCONNECT_PERIOD m_requestSimDataPeriod = SIMCONNECT_PERIOD_NEVER; //!< how often do we query ground elevation
|
||||
bool m_validRequestId = false;
|
||||
bool m_validObjectId = false;
|
||||
bool m_confirmedAdded = false;
|
||||
@@ -103,9 +109,12 @@ namespace BlackSimPlugin
|
||||
//! Find which callsign belongs to the object id
|
||||
BlackMisc::Aviation::CCallsign getCallsignForObjectId(DWORD objectId) const;
|
||||
|
||||
//! Find which callsign belongs to the object id
|
||||
//! Get object per object id
|
||||
CSimConnectObject getSimObjectForObjectId(DWORD objectId) const;
|
||||
|
||||
//! Get object per request id
|
||||
CSimConnectObject getSimObjectForRequestId(DWORD requestId) const;
|
||||
|
||||
//! Is the object id one of our AI objects?
|
||||
bool isKnownSimObjectId(DWORD objectId) const;
|
||||
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
|
||||
#include "simulatorfsx.h"
|
||||
#include "blackcore/application.h"
|
||||
#include "blackmisc/interpolatorlinear.h"
|
||||
#include "blackmisc/network/textmessage.h"
|
||||
#include "blackmisc/simulation/fscommon/bcdconversions.h"
|
||||
#include "blackmisc/simulation/fsx/simconnectutilities.h"
|
||||
#include "blackmisc/simulation/simulatorplugininfo.h"
|
||||
#include "blackmisc/simulation/aircraftmodel.h"
|
||||
#include "blackmisc/simulation/interpolatorlinear.h"
|
||||
#include "blackmisc/simulation/interpolationhints.h"
|
||||
#include "blackmisc/simulation/simulatorplugininfo.h"
|
||||
#include "blackmisc/aviation/airportlist.h"
|
||||
#include "blackmisc/geo/elevationplane.h"
|
||||
#include "blackmisc/logmessage.h"
|
||||
#include "blackmisc/threadutils.h"
|
||||
#include "blackmisc/verify.h"
|
||||
@@ -49,11 +51,11 @@ namespace BlackSimPlugin
|
||||
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");
|
||||
this->m_realityBubbleTimer.setInterval(20 * 1000);
|
||||
m_realityBubbleTimer.setInterval(20 * 1000);
|
||||
connect(&m_realityBubbleTimer, &QTimer::timeout, this, &CSimulatorFsx::ps_addAircraftCurrentlyOutOfBubble);
|
||||
|
||||
m_useFsuipc = true; // Temporarily enabled until Simconnect Weather is implemented.
|
||||
this->m_interpolator = new CInterpolatorLinear(remoteAircraftProvider, this);
|
||||
m_interpolator = new CInterpolatorLinear(remoteAircraftProvider, this);
|
||||
m_defaultModel =
|
||||
{
|
||||
"Boeing 737-800 Paint1",
|
||||
@@ -155,8 +157,8 @@ namespace BlackSimPlugin
|
||||
// initial position if interpolator has data, otherwise do nothing
|
||||
setInitialAircraftSituation(addedAircraft); // set interpolated data/parts if available
|
||||
|
||||
const DWORD requestId = m_requestId++;
|
||||
SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxPosition(addedAircraft.getSituation());
|
||||
const DWORD requestId = obtainRequestId();
|
||||
SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxPosition(addedAircraft.getSituation(), CInterpolationHints());
|
||||
const QString modelString(addedAircraft.getModelString());
|
||||
|
||||
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
|
||||
@@ -195,9 +197,9 @@ namespace BlackSimPlugin
|
||||
if (!this->isSimulating()) { return false; }
|
||||
|
||||
// actually those data should be the same as ownAircraft
|
||||
CComSystem newCom1 = ownAircraft.getCom1System();
|
||||
CComSystem newCom2 = ownAircraft.getCom2System();
|
||||
CTransponder newTransponder = ownAircraft.getTransponder();
|
||||
const CComSystem newCom1 = ownAircraft.getCom1System();
|
||||
const CComSystem newCom2 = ownAircraft.getCom2System();
|
||||
const CTransponder newTransponder = ownAircraft.getTransponder();
|
||||
|
||||
bool changed = false;
|
||||
if (newCom1.getFrequencyActive() != this->m_simCom1.getFrequencyActive())
|
||||
@@ -356,7 +358,7 @@ namespace BlackSimPlugin
|
||||
|
||||
void CSimulatorFsx::onSimStopped()
|
||||
{
|
||||
int oldStatus = getSimulatorStatus();
|
||||
const int oldStatus = getSimulatorStatus();
|
||||
m_simSimulating = false;
|
||||
emitSimulatorCombinedStatus(oldStatus);
|
||||
}
|
||||
@@ -372,6 +374,18 @@ namespace BlackSimPlugin
|
||||
disconnectFrom();
|
||||
}
|
||||
|
||||
DWORD CSimulatorFsx::obtainRequestId()
|
||||
{
|
||||
DWORD id = m_requestId++;
|
||||
if (id < FirstRequestId)
|
||||
{
|
||||
// overflow, restart
|
||||
id = FirstRequestId;
|
||||
m_requestId = FirstRequestId + 1;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void CSimulatorFsx::updateOwnAircraftFromSimulator(const DataDefinitionOwnAircraft &simulatorOwnAircraft)
|
||||
{
|
||||
CSimulatedAircraft myAircraft(getOwnAircraft());
|
||||
@@ -390,30 +404,33 @@ namespace BlackSimPlugin
|
||||
aircraftSituation.setBank(CAngle(-simulatorOwnAircraft.bank, CAngleUnit::deg()));
|
||||
aircraftSituation.setHeading(CHeading(simulatorOwnAircraft.trueHeading, CHeading::True, CAngleUnit::deg()));
|
||||
aircraftSituation.setGroundSpeed(CSpeed(simulatorOwnAircraft.velocity, CSpeedUnit::kts()));
|
||||
aircraftSituation.setGroundElevation(CAltitude(simulatorOwnAircraft.elevation, CAltitude::MeanSeaLevel, CLengthUnit::m()));
|
||||
aircraftSituation.setGroundElevation(CAltitude(simulatorOwnAircraft.elevation, CAltitude::MeanSeaLevel, CLengthUnit::ft()));
|
||||
aircraftSituation.setAltitude(CAltitude(simulatorOwnAircraft.altitude, CAltitude::MeanSeaLevel, CLengthUnit::ft()));
|
||||
|
||||
CAircraftLights lights(simulatorOwnAircraft.lightStrobe,
|
||||
simulatorOwnAircraft.lightLanding,
|
||||
simulatorOwnAircraft.lightTaxi,
|
||||
simulatorOwnAircraft.lightBeacon,
|
||||
simulatorOwnAircraft.lightNav,
|
||||
simulatorOwnAircraft.lightLogo);
|
||||
|
||||
QList<bool> helperList {simulatorOwnAircraft.engine1Combustion != 0, simulatorOwnAircraft.engine2Combustion != 0,
|
||||
simulatorOwnAircraft.engine3Combustion != 0, simulatorOwnAircraft.engine4Combustion != 0 };
|
||||
const CAircraftLights lights(simulatorOwnAircraft.lightStrobe,
|
||||
simulatorOwnAircraft.lightLanding,
|
||||
simulatorOwnAircraft.lightTaxi,
|
||||
simulatorOwnAircraft.lightBeacon,
|
||||
simulatorOwnAircraft.lightNav,
|
||||
simulatorOwnAircraft.lightLogo);
|
||||
|
||||
CAircraftEngineList engines;
|
||||
const QList<bool> helperList
|
||||
{
|
||||
simulatorOwnAircraft.engine1Combustion != 0, simulatorOwnAircraft.engine2Combustion != 0,
|
||||
simulatorOwnAircraft.engine3Combustion != 0, simulatorOwnAircraft.engine4Combustion != 0
|
||||
};
|
||||
|
||||
for (int index = 0; index < simulatorOwnAircraft.numberOfEngines; ++index)
|
||||
{
|
||||
engines.push_back(CAircraftEngine(index + 1, helperList.at(index)));
|
||||
}
|
||||
|
||||
CAircraftParts parts(lights, simulatorOwnAircraft.gearHandlePosition,
|
||||
simulatorOwnAircraft.flapsHandlePosition * 100,
|
||||
simulatorOwnAircraft.spoilersHandlePosition,
|
||||
engines,
|
||||
simulatorOwnAircraft.simOnGround);
|
||||
const CAircraftParts parts(lights, simulatorOwnAircraft.gearHandlePosition,
|
||||
simulatorOwnAircraft.flapsHandlePosition * 100,
|
||||
simulatorOwnAircraft.spoilersHandlePosition,
|
||||
engines,
|
||||
simulatorOwnAircraft.simOnGround);
|
||||
|
||||
// set values
|
||||
updateOwnSituation(aircraftSituation);
|
||||
@@ -463,6 +480,39 @@ namespace BlackSimPlugin
|
||||
}
|
||||
}
|
||||
|
||||
void CSimulatorFsx::updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionRemoteAircraftSimData &remoteAircraftData)
|
||||
{
|
||||
CInterpolationHints &hints = m_hints[simObject.getCallsign()];
|
||||
|
||||
// we only need elevation near ground, in other cases we ignore it
|
||||
if (remoteAircraftData.aboveGround() <= 100.0)
|
||||
{
|
||||
CElevationPlane elevation(remoteAircraftData.latitude, remoteAircraftData.longitude, remoteAircraftData.elevation);
|
||||
elevation.setSinglePointRadius();
|
||||
|
||||
// const QString debug(hints.debugInfo(elevation));
|
||||
hints.setElevation(elevation); // update elevation
|
||||
hints.setCGAboveGround({ remoteAircraftData.cgToGround, CLengthUnit::ft() });
|
||||
|
||||
// set it in the remote aircraft provider
|
||||
this->updateAircraftGroundElevation(simObject.getCallsign(), elevation);
|
||||
// switch to fast updates
|
||||
if (simObject.getSimDataPeriod() != SIMCONNECT_PERIOD_VISUAL_FRAME)
|
||||
{
|
||||
this->requestDataForSimObject(simObject, SIMCONNECT_PERIOD_VISUAL_FRAME);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hints.resetElevation();
|
||||
// switch to slow updates
|
||||
if (simObject.getSimDataPeriod() != SIMCONNECT_PERIOD_SECOND)
|
||||
{
|
||||
this->requestDataForSimObject(simObject, SIMCONNECT_PERIOD_SECOND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSimulatorFsx::updateOwnAircraftFromSimulator(const DataDefinitionClientAreaSb &sbDataArea)
|
||||
{
|
||||
CTransponder::TransponderMode newMode;
|
||||
@@ -475,7 +525,7 @@ namespace BlackSimPlugin
|
||||
newMode = sbDataArea.isStandby() ? CTransponder::StateStandby : CTransponder::ModeC;
|
||||
}
|
||||
const CSimulatedAircraft myAircraft(this->getOwnAircraft());
|
||||
bool changed = (myAircraft.getTransponderMode() != newMode);
|
||||
const bool changed = (myAircraft.getTransponderMode() != newMode);
|
||||
if (!changed) { return; }
|
||||
CTransponder xpdr = myAircraft.getTransponder();
|
||||
xpdr.setTransponderMode(newMode);
|
||||
@@ -511,7 +561,7 @@ namespace BlackSimPlugin
|
||||
}
|
||||
|
||||
// P3D also has SimConnect_AIReleaseControlEx;
|
||||
DWORD requestId = m_requestId++;
|
||||
const DWORD requestId = obtainRequestId();
|
||||
HRESULT hr = SimConnect_AIReleaseControl(m_hSimConnect, objectId, static_cast<SIMCONNECT_DATA_REQUEST_ID>(requestId));
|
||||
if (hr == S_OK)
|
||||
{
|
||||
@@ -683,6 +733,7 @@ namespace BlackSimPlugin
|
||||
|
||||
// call in SIM
|
||||
SimConnect_AIRemoveObject(m_hSimConnect, static_cast<SIMCONNECT_OBJECT_ID>(simObject.getObjectId()), static_cast<SIMCONNECT_DATA_REQUEST_ID>(m_requestId++));
|
||||
m_hints.remove(simObject.getCallsign());
|
||||
|
||||
// mark in provider
|
||||
bool updated = updateAircraftRendered(callsign, false);
|
||||
@@ -809,7 +860,6 @@ namespace BlackSimPlugin
|
||||
// values used for position and parts
|
||||
bool isOnGround = false;
|
||||
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)
|
||||
@@ -823,43 +873,13 @@ namespace BlackSimPlugin
|
||||
Q_ASSERT_X(simObj.hasValidRequestAndObjectId(), Q_FUNC_INFO, "Missing ids");
|
||||
|
||||
IInterpolator::InterpolationStatus 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.setSupportsParts(enableAircraftParts && aircraftWithParts.contains(callsign));
|
||||
CAircraftPartsList parts;
|
||||
if (enableAircraftParts && partsStatus.allTrue())
|
||||
{
|
||||
parts = this->m_interpolator->getPartsBeforeTime(callsign, interpolatedSituation.getMSecsSinceEpoch(), partsStatus);
|
||||
}
|
||||
const CInterpolationHints hints(m_hints[simObj.getCallsign()]);
|
||||
const CAircraftSituation interpolatedSituation = this->m_interpolator->getInterpolatedSituation(callsign, currentTimestamp, hints, interpolatorStatus);
|
||||
|
||||
if (interpolatorStatus.allTrue())
|
||||
{
|
||||
// update situation
|
||||
SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxPosition(interpolatedSituation);
|
||||
|
||||
//! \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.isSupportingParts() && !parts.isEmpty())
|
||||
{
|
||||
// we have parts, and use the closest ground
|
||||
|
||||
// \fixme onGround flag is not synchronized with positions and causes jumps during takeoff/landing.
|
||||
// We need to find a better way to synchronize both. Until then, use it for a very small speed range only.
|
||||
// This covers taxiing aircraft as well as a hovering helicopter.
|
||||
double groundSpeedKnots = interpolatedSituation.getGroundSpeed().value(CSpeedUnit::kts());
|
||||
if (groundSpeedKnots < 50) { isOnGround = parts.front().isOnGround(); }
|
||||
else { isOnGround = interpolatedSituation.isOnGroundGuessed(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
isOnGround = interpolatedSituation.isOnGroundGuessed();
|
||||
}
|
||||
|
||||
position.OnGround = isOnGround ? 1U : 0U;
|
||||
SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxPosition(interpolatedSituation, hints);
|
||||
HRESULT hr = S_OK;
|
||||
hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPosition,
|
||||
static_cast<SIMCONNECT_OBJECT_ID>(simObj.getObjectId()), 0, 0,
|
||||
@@ -873,10 +893,16 @@ namespace BlackSimPlugin
|
||||
|
||||
if (interpolatorStatus.didInterpolationSucceed())
|
||||
{
|
||||
const CCallsignSet aircraftWithParts(this->remoteAircraftSupportingParts()); // optimization, fetch all parts supporting aircraft in one step (one lock)
|
||||
IInterpolator::PartsStatus partsStatus;
|
||||
partsStatus.setSupportsParts(enableAircraftParts && aircraftWithParts.contains(callsign));
|
||||
|
||||
// aircraft parts inside "interpolator if", as no parts can be set without situation
|
||||
// situation is used to anticipate parts if other client does not send them
|
||||
if (enableAircraftParts)
|
||||
{
|
||||
CAircraftPartsList parts;
|
||||
parts = this->m_interpolator->getPartsBeforeTime(callsign, interpolatedSituation.getMSecsSinceEpoch(), partsStatus);
|
||||
updateRemoteAircraftParts(simObj, parts, partsStatus, interpolatedSituation, isOnGround); // update and retrieve parts in the same step
|
||||
}
|
||||
}
|
||||
@@ -971,22 +997,20 @@ namespace BlackSimPlugin
|
||||
return hr == S_OK;
|
||||
}
|
||||
|
||||
SIMCONNECT_DATA_INITPOSITION CSimulatorFsx::aircraftSituationToFsxPosition(const CAircraftSituation &situation, bool guessOnGround)
|
||||
SIMCONNECT_DATA_INITPOSITION CSimulatorFsx::aircraftSituationToFsxPosition(const CAircraftSituation &situation, const CInterpolationHints &hints)
|
||||
{
|
||||
SIMCONNECT_DATA_INITPOSITION position;
|
||||
position.Latitude = situation.latitude().value(CAngleUnit::deg());
|
||||
position.Longitude = situation.longitude().value(CAngleUnit::deg());
|
||||
position.Altitude = situation.getAltitude().value(CLengthUnit::ft());
|
||||
position.Altitude = situation.getCorrectedAltitude(hints.getCGAboveGround()).value(CLengthUnit::ft());
|
||||
position.Heading = situation.getHeading().value(CAngleUnit::deg());
|
||||
position.Airspeed = situation.getGroundSpeed().value(CSpeedUnit::kts());
|
||||
|
||||
// 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.Airspeed = situation.getGroundSpeed().value(CSpeedUnit::kts());
|
||||
bool onGround = false;
|
||||
if (guessOnGround)
|
||||
{
|
||||
onGround = situation.isOnGroundGuessed();
|
||||
}
|
||||
|
||||
const bool onGround = situation.isOnGroundGuessed(hints.getCGAboveGround());
|
||||
position.OnGround = onGround ? 1U : 0U;
|
||||
return position;
|
||||
}
|
||||
@@ -1047,6 +1071,21 @@ namespace BlackSimPlugin
|
||||
}
|
||||
}
|
||||
|
||||
bool CSimulatorFsx::requestDataForSimObject(const CSimConnectObject &simObject, SIMCONNECT_PERIOD period)
|
||||
{
|
||||
if (!simObject.hasValidRequestAndObjectId()) { return false; }
|
||||
if (simObject.getSimDataPeriod() == period) { return true; } // already queried like this
|
||||
|
||||
const HRESULT result = SimConnect_RequestDataOnSimObject(m_hSimConnect, simObject.getRequestId(), CSimConnectDefinitions::DataRemoteAircraftSimData, simObject.getObjectId(), period, SIMCONNECT_CLIENT_DATA_REQUEST_FLAG_CHANGED);
|
||||
if (result == S_OK)
|
||||
{
|
||||
m_simConnectObjects[simObject.getCallsign()].setSimDataPeriod(period);
|
||||
return true;
|
||||
}
|
||||
CLogMessage(this).error("Cannot request data on object '%1'") << simObject.getObjectId();
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSimulatorFsx::initInternalsObject()
|
||||
{
|
||||
CSimulatorFsCommon::initInternalsObject();
|
||||
@@ -1068,7 +1107,7 @@ namespace BlackSimPlugin
|
||||
m_syncDeferredCounter = 0;
|
||||
m_skipCockpitUpdateCycles = 0;
|
||||
m_interpolationRequest = 0;
|
||||
m_requestId = 1;
|
||||
m_requestId = FirstRequestId;
|
||||
m_dispatchErrors = 0;
|
||||
m_receiveExceptionCount = 0;
|
||||
CSimulatorFsCommon::reset();
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "simconnectobject.h"
|
||||
#include "../fscommon/simulatorfscommon.h"
|
||||
#include "blackcore/simulator.h"
|
||||
#include "blackmisc/interpolatorlinear.h"
|
||||
#include "blackmisc/simulation/interpolatorlinear.h"
|
||||
#include "blackmisc/simulation/simulatorplugininfo.h"
|
||||
#include "blackmisc/simulation/simulatorsettings.h"
|
||||
#include "blackmisc/simulation/aircraftmodel.h"
|
||||
@@ -102,27 +102,6 @@ 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(const DataDefinitionOwnAircraft &simulatorOwnAircraft);
|
||||
|
||||
//! Update from SB client area
|
||||
void updateOwnAircraftFromSimulator(const DataDefinitionClientAreaSb &sbDataArea);
|
||||
|
||||
//! 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);
|
||||
|
||||
//! The simconnect related objects
|
||||
const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; }
|
||||
|
||||
protected:
|
||||
//! \name Interface implementations
|
||||
//! @{
|
||||
@@ -149,7 +128,8 @@ namespace BlackSimPlugin
|
||||
//! \remark kind of cleanup function, in an ideal this should never need to cleanup something
|
||||
BlackMisc::Aviation::CCallsignSet ps_physicallyRemoveAircraftNotInProvider();
|
||||
|
||||
//! Handle that an object has been added
|
||||
//! Handle 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
|
||||
bool ps_deferredSimulatorReportedObjectAdded(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Try to add the aircraft currently out of bubble
|
||||
@@ -171,6 +151,9 @@ namespace BlackSimPlugin
|
||||
//! Simulator is going down
|
||||
void onSimExit();
|
||||
|
||||
//! Get new request id, overflow safe
|
||||
DWORD obtainRequestId();
|
||||
|
||||
//! Init when connected
|
||||
HRESULT initWhenConnected();
|
||||
|
||||
@@ -185,10 +168,34 @@ namespace BlackSimPlugin
|
||||
|
||||
//! Update remote airacraft parts (send to FSX)
|
||||
bool updateRemoteAircraftParts(const CSimConnectObject &simObj, const BlackMisc::Aviation::CAircraftPartsList &parts,
|
||||
BlackMisc::IInterpolator::PartsStatus partsStatus, const BlackMisc::Aviation::CAircraftSituation &interpolatedSituation, bool isOnGround) const;
|
||||
BlackMisc::Simulation::IInterpolator::PartsStatus partsStatus, const BlackMisc::Aviation::CAircraftSituation &interpolatedSituation, bool isOnGround) const;
|
||||
|
||||
//! Called when data about our own aircraft are received
|
||||
void updateOwnAircraftFromSimulator(const DataDefinitionOwnAircraft &simulatorOwnAircraft);
|
||||
|
||||
//! Remote aircraft data sent from simulator
|
||||
void updateRemoteAircraftFromSimulator(const CSimConnectObject &simObject, const DataDefinitionRemoteAircraftSimData &remoteAircraftData);
|
||||
|
||||
//! Update from SB client area
|
||||
void updateOwnAircraftFromSimulator(const DataDefinitionClientAreaSb &sbDataArea);
|
||||
|
||||
//! 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);
|
||||
|
||||
//! Display receive exceptions?
|
||||
bool stillDisplayReceiveExceptions();
|
||||
|
||||
//! The simconnect related objects
|
||||
const CSimConnectObjects &getSimConnectObjects() const { return m_simConnectObjects; }
|
||||
|
||||
//! Format conversion
|
||||
SIMCONNECT_DATA_INITPOSITION aircraftSituationToFsxPosition(const BlackMisc::Aviation::CAircraftSituation &situation, bool guessOnGround = true);
|
||||
SIMCONNECT_DATA_INITPOSITION aircraftSituationToFsxPosition(const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Simulation::CInterpolationHints &hints);
|
||||
|
||||
//! Sync time with user's computer
|
||||
void synchronizeTime(const BlackMisc::PhysicalQuantities::CTime &zuluTimeSim, const BlackMisc::PhysicalQuantities::CTime &localTimeSim);
|
||||
@@ -199,6 +206,9 @@ namespace BlackSimPlugin
|
||||
//! Reload weather settings
|
||||
void reloadWeatherSettings();
|
||||
|
||||
//! Request data for a simObject (aka remote aircraft)
|
||||
bool requestDataForSimObject(const CSimConnectObject &simObject, SIMCONNECT_PERIOD period = SIMCONNECT_PERIOD_SECOND);
|
||||
|
||||
//! FSX position as string
|
||||
static QString fsxPositionToString(const SIMCONNECT_DATA_INITPOSITION &position);
|
||||
|
||||
@@ -207,17 +217,19 @@ namespace BlackSimPlugin
|
||||
|
||||
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 FirstRequestId = static_cast<int>(CSimConnectDefinitions::RequestEndMarker);
|
||||
|
||||
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
|
||||
int m_syncDeferredCounter = 0; //!< Set when synchronized, used to wait some time
|
||||
int m_simConnectTimerId = -1; //!< Timer identifier
|
||||
int m_skipCockpitUpdateCycles = 0; //!< Skip some update cycles to allow changes in simulator cockpit to be set
|
||||
int m_skipCockpitUpdateCycles = 0; //!< skip some update cycles to allow changes in simulator cockpit to be set
|
||||
int m_interpolationRequest = 0; //!< current interpolation request
|
||||
int m_dispatchErrors = 0; //!< number of dispatched failed, \sa ps_dispatch
|
||||
int m_receiveExceptionCount = 0; //!< exceptions
|
||||
DWORD m_requestId = 1; //!< request id
|
||||
DWORD m_requestId = FirstRequestId; //!< request id, use obtainRequestId() to get id
|
||||
HANDLE m_hSimConnect = nullptr; //!< handle to SimConnect object
|
||||
CSimConnectObjects m_simConnectObjects; //!< AI objects and their object / request ids
|
||||
BlackMisc::Simulation::CSimulatedAircraftList m_outOfRealityBubble; //!< aircraft removed by FSX because they are out of reality bubble
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace BlackSimPlugin
|
||||
{
|
||||
case SystemEventSimStatus:
|
||||
{
|
||||
bool running = event->dwData ? true : false;
|
||||
const bool running = event->dwData ? true : false;
|
||||
if (running)
|
||||
{
|
||||
simulatorFsx->onSimRunning();
|
||||
@@ -95,7 +95,7 @@ namespace BlackSimPlugin
|
||||
}
|
||||
case SystemEventPause:
|
||||
{
|
||||
bool p = event->dwData ? true : false;
|
||||
const bool p = event->dwData ? true : false;
|
||||
if (simulatorFsx->m_simPaused != p)
|
||||
{
|
||||
simulatorFsx->m_simPaused = p;
|
||||
@@ -110,7 +110,7 @@ namespace BlackSimPlugin
|
||||
}
|
||||
case SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE:
|
||||
{
|
||||
SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *event = static_cast<SIMCONNECT_RECV_EVENT_OBJECT_ADDREMOVE *>(pData);
|
||||
const 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)
|
||||
@@ -151,25 +151,37 @@ namespace BlackSimPlugin
|
||||
case SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID:
|
||||
{
|
||||
SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *event = static_cast<SIMCONNECT_RECV_ASSIGNED_OBJECT_ID *>(pData);
|
||||
const DWORD requestID = event->dwRequestID;
|
||||
const DWORD objectID = event->dwObjectID;
|
||||
bool success = simulatorFsx->setSimConnectObjectId(requestID, objectID);
|
||||
const DWORD requestId = event->dwRequestID;
|
||||
const DWORD objectId = event->dwObjectID;
|
||||
bool success = simulatorFsx->setSimConnectObjectId(requestId, objectId);
|
||||
if (!success) { break; } // not an request ID of ours
|
||||
|
||||
success = simulatorFsx->simulatorReportedObjectAdded(objectID);
|
||||
if (!success)
|
||||
success = simulatorFsx->simulatorReportedObjectAdded(objectId);
|
||||
if (success)
|
||||
{
|
||||
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);
|
||||
const CSimConnectObject simObject = simulatorFsx->getSimConnectObjects().getSimObjectForObjectId(objectId);
|
||||
HRESULT result = simulatorFsx->requestDataForSimObject(simObject);
|
||||
Q_UNUSED(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
const CSimulatedAircraft remoteAircraft(simulatorFsx->getSimConnectObjects().getSimObjectForObjectId(objectId).getAircraft());
|
||||
const CStatusMessage msgAdd = CStatusMessage(simulatorFsx).error("Cannot add object %1") << objectId;
|
||||
CLogMessage::preformatted(msgAdd);
|
||||
emit simulatorFsx->physicallyAddingRemoteModelFailed(remoteAircraft, msgAdd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE:
|
||||
{
|
||||
// SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *)pData;
|
||||
break;
|
||||
}
|
||||
case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
|
||||
{
|
||||
SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA *) pData;
|
||||
switch (pObjData->dwRequestID)
|
||||
const DWORD requestId = pObjData->dwRequestID;
|
||||
switch (requestId)
|
||||
{
|
||||
case CSimConnectDefinitions::RequestOwnAircraft:
|
||||
{
|
||||
@@ -203,6 +215,21 @@ namespace BlackSimPlugin
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
static_assert(sizeof(DataDefinitionRemoteAircraftSimData) == 5 * sizeof(double), "DataDefinitionRemoteAircraftSimData has an incorrect size.");
|
||||
const CSimConnectObject simObj = simulatorFsx->getSimConnectObjects().getSimObjectForRequestId(requestId);
|
||||
if (simObj.hasValidRequestAndObjectId())
|
||||
{
|
||||
const DWORD objectId = pObjData->dwObjectID;
|
||||
const DataDefinitionRemoteAircraftSimData *remoteAircraftSimData = (DataDefinitionRemoteAircraftSimData *)&pObjData->dwData;
|
||||
// extra check, but ids should be the same
|
||||
if (objectId == simObj.getObjectId())
|
||||
{
|
||||
simulatorFsx->updateRemoteAircraftFromSimulator(simObj, *remoteAircraftSimData);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user