8 #include <QElapsedTimer>
10 #include <QStringBuilder>
13 #include "../fscommon/simulatorfscommonfunctions.h"
36 using namespace swift::config;
38 using namespace swift::misc::aviation;
39 using namespace swift::misc::physical_quantities;
40 using namespace swift::misc::geo;
41 using namespace swift::misc::network;
42 using namespace swift::misc::math;
43 using namespace swift::misc::simulation;
44 using namespace swift::misc::simulation::fscommon;
45 using namespace swift::misc::simulation::fsx;
46 using namespace swift::misc::simulation::settings;
48 using namespace swift::simplugin::fscommon;
50 namespace swift::simplugin::fsxcommon
56 :
CSimulatorFsCommon(info, ownAircraftProvider, remoteAircraftProvider, clientProvider, parent)
58 Q_ASSERT_X(ownAircraftProvider, Q_FUNC_INFO,
"Missing provider");
59 Q_ASSERT_X(remoteAircraftProvider, Q_FUNC_INFO,
"Missing provider");
60 Q_ASSERT_X(
sApp, Q_FUNC_INFO,
"Missing global object");
62 m_simObjectTimer.setInterval(AddPendingAircraftIntervalMs);
66 connect(&m_simObjectTimer, &QTimer::timeout,
this, &CSimulatorFsxCommon::timerBasedObjectAddOrRemove);
92 this->initDataDefinitionsWhenConnected();
94 m_timerId = this->startTimer(DispatchIntervalMs);
101 if (!m_simConnected) {
return true; }
102 m_simSimulating =
false;
103 m_traceAutoUntilTs = -1;
104 m_traceSendId =
false;
111 m_simConnected =
false;
115 return CSimulatorFsCommon::disconnectFrom();
121 return this->physicallyAddRemoteAircraftImpl(newRemoteAircraft, ExternalCall);
124 bool CSimulatorFsxCommon::updateCOMFromSwiftToSimulator(
const CFrequency &newFreq,
const CFrequency &lastSimFreq,
127 if (newFreq == lastSimFreq) {
return false; }
129 if (CComSystem::isExclusiveWithin8_33kHzChannel(newFreq) && last25kHzSimFreq.
isNull())
133 last25kHzSimFreq = lastSimFreq;
137 if (CComSystem::isWithin25kHzChannel(newFreq))
141 SimConnect_TransmitClientEvent(
m_hSimConnect, 0,
id, CBcdConversions::comFrequencyToBcdHz(newFreq),
142 SIMCONNECT_GROUP_PRIORITY_HIGHEST,
143 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
154 if (originator == this->
identifier()) {
return false; }
162 bool changed =
false;
165 m_lastCom1Active, EventSetCom1Active);
167 m_lastCom1Standby, EventSetCom1Standby);
169 m_lastCom2Active, EventSetCom2Active);
171 m_lastCom2Standby, EventSetCom2Standby);
178 byte standby = newTransponder.
isInStandby() ? 1U : 0U;
181 hr += SimConnect_SetClientData(
m_hSimConnect, ClientAreaSquawkBox,
183 SIMCONNECT_CLIENT_DATA_SET_FLAG_DEFAULT, 0, 1, &ident);
184 hr += SimConnect_SetClientData(
m_hSimConnect, ClientAreaSquawkBox,
186 SIMCONNECT_CLIENT_DATA_SET_FLAG_DEFAULT, 0, 1, &standby);
197 "SB sent: ident " % QString::number(ident) % u
" standby " % QString::number(standby);
211 hr += SimConnect_SetDataOnSimObject(
m_hSimConnect, CSimConnectDefinitions::DataTransponderModeMSFS,
212 SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_DATA_SET_FLAG_DEFAULT, 0,
230 if (originator == this->
identifier()) {
return false; }
241 QByteArray m = message.
getMessage().toLatin1().constData();
244 SIMCONNECT_TEXT_TYPE type = SIMCONNECT_TEXT_TYPE_PRINT_BLACK;
247 case CStatusMessage::SeverityDebug:
return;
248 case CStatusMessage::SeverityInfo: type = SIMCONNECT_TEXT_TYPE_PRINT_GREEN;
break;
249 case CStatusMessage::SeverityWarning: type = SIMCONNECT_TEXT_TYPE_PRINT_YELLOW;
break;
250 case CStatusMessage::SeverityError: type = SIMCONNECT_TEXT_TYPE_PRINT_RED;
break;
253 SimConnect_Text(
m_hSimConnect, type, 7.5, EventTextMessage,
static_cast<DWORD>(m.size()), m.data());
259 QByteArray m = message.
asString(
true,
true).toLatin1().constData();
262 SIMCONNECT_TEXT_TYPE type = SIMCONNECT_TEXT_TYPE_PRINT_BLACK;
264 else if (message.
isPrivateMessage()) { type = SIMCONNECT_TEXT_TYPE_PRINT_YELLOW; }
265 else if (message.
isRadioMessage()) { type = SIMCONNECT_TEXT_TYPE_PRINT_GREEN; }
268 SimConnect_Text(
m_hSimConnect, type, 7.5, EventTextMessage,
static_cast<DWORD>(m.size()), m.data());
283 m_addPendingAircraft.keys());
290 if (!CBuildConfig::isLocalDeveloperDebugBuild()) {
return msgs; }
291 msgs = CSimulatorFsCommon::debugVerifyStateAfterAllAircraftRemoved();
297 if (!m_simConnectObjectsPositionAndPartsTraces.isEmpty())
312 static const QString specificInfo(
313 "dispatch #: %1 %2 times (cur/max): %3ms (%4ms) %5ms (%6ms) %7 %8 simData#: %9");
314 return specificInfo.arg(m_dispatchProcCount)
315 .arg(m_dispatchProcEmptyCount)
316 .arg(m_dispatchTimeMs)
317 .arg(m_dispatchProcTimeMs)
318 .arg(m_dispatchMaxTimeMs)
319 .arg(m_dispatchProcMaxTimeMs)
320 .arg(CSimConnectUtilities::simConnectReceiveIdToString(
static_cast<DWORD>(m_dispatchReceiveIdMaxTime)),
321 requestIdToString(m_dispatchRequestIdMaxTime))
322 .arg(m_requestSimObjectDataCount);
331 if (reference.
isNull()) {
return false; }
342 simObject.
getObjectId(), 0, 0,
sizeof(SIMCONNECT_DATA_INITPOSITION),
344 simObject,
"Cannot request AI elevation", Q_FUNC_INFO,
"SimConnect_SetDataOnSimObject");
348 const bool ok = this->requestTerrainProbeData(simObject, aircraftCallsign);
355 if (m_traceSendId) {
return true; }
356 if (m_traceAutoUntilTs < 0) {
return false; }
357 const qint64 ts = QDateTime::currentMSecsSinceEpoch();
358 const bool trace = ts <= m_traceAutoUntilTs;
364 m_traceSendId = trace;
365 m_traceAutoUntilTs = -1;
370 m_useAddSimulatedObj = enabled;
379 m_useSbOffsets = enabled;
388 m_dispatchProcCount = 0;
389 m_dispatchProcEmptyCount = 0;
390 m_dispatchMaxTimeMs = -1;
391 m_dispatchProcMaxTimeMs = -1;
392 m_dispatchTimeMs = -1;
393 m_dispatchProcTimeMs = -1;
394 m_requestSimObjectDataCount = 0;
395 m_dispatchReceiveIdLast = SIMCONNECT_RECV_ID_NULL;
396 m_dispatchReceiveIdMaxTime = SIMCONNECT_RECV_ID_NULL;
399 CSimulatorPluginCommon::resetAircraftStatistics();
412 byte sbNetworkConnected = connected ? 1u : 0u;
413 const HRESULT hr = SimConnect_SetClientData(
m_hSimConnect, ClientAreaSquawkBox,
415 SIMCONNECT_CLIENT_DATA_SET_FLAG_DEFAULT, 0, 1, &sbNetworkConnected);
418 ISimulator::setFlightNetworkConnected(connected);
437 this->sendRemoteAircraftPartsToSimulator(simObject, parts);
446 static_cast<SIMCONNECT_OBJECT_ID
>(simObject.
getObjectId()), 0, 0,
447 sizeof(SIMCONNECT_DATA_INITPOSITION), &position),
448 traceSendId, simObject,
"Failed to set position", Q_FUNC_INFO,
"SimConnect_SetDataOnSimObject");
449 if (hr == S_OK) { u++; }
460 v = (requestId - RequestSimObjTerrainProbeStart) / MaxSimObjProbes;
466 bool CSimulatorFsxCommon::stillDisplayReceiveExceptions()
468 m_receiveExceptionCount++;
469 return m_receiveExceptionCount < IgnoreReceiveExceptions;
472 CSimConnectObject CSimulatorFsxCommon::getSimObjectForObjectId(
DWORD objectId)
const
477 void CSimulatorFsxCommon::setSimConnected()
479 m_simConnected =
true;
485 const QPointer<CSimulatorFsxCommon> myself(
this);
487 if (!myself) {
return; }
488 myself->initSimulatorInternals();
492 void CSimulatorFsxCommon::onSimRunning()
494 const QPointer<CSimulatorFsxCommon> myself(
this);
496 if (!myself) {
return; }
497 m_simulatingChangedTs = QDateTime::currentMSecsSinceEpoch();
498 this->onSimRunningDeferred(m_simulatingChangedTs);
502 void CSimulatorFsxCommon::onSimRunningDeferred(qint64 referenceTs)
504 if (m_simSimulating) {
return; }
505 if (referenceTs != m_simulatingChangedTs) {
return; }
506 m_simSimulating =
true;
507 m_simConnected =
true;
515 m_useSbOffsets =
false;
520 SimConnect_RequestDataOnSimObject(
m_hSimConnect, CSimConnectDefinitions::RequestOwnAircraft,
521 CSimConnectDefinitions::DataOwnAircraft, SIMCONNECT_OBJECT_ID_USER,
522 SIMCONNECT_PERIOD_VISUAL_FRAME),
523 "Cannot request own aircraft data", Q_FUNC_INFO,
"SimConnect_RequestDataOnSimObject");
526 SimConnect_RequestDataOnSimObject(
m_hSimConnect, CSimConnectDefinitions::RequestOwnAircraftTitle,
527 CSimConnectDefinitions::DataOwnAircraftTitle, SIMCONNECT_OBJECT_ID_USER,
528 SIMCONNECT_PERIOD_SECOND, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED),
529 "Cannot request title", Q_FUNC_INFO,
"SimConnect_RequestDataOnSimObject");
541 SIMCONNECT_CLIENT_DATA_PERIOD_SECOND,
542 SIMCONNECT_CLIENT_DATA_REQUEST_FLAG_CHANGED),
543 "Cannot request client data", Q_FUNC_INFO,
"SimConnect_RequestClientData");
549 CSimConnectDefinitions::DataTransponderModeMSFS,
550 SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_VISUAL_FRAME,
551 SIMCONNECT_DATA_REQUEST_FLAG_CHANGED),
552 "Cannot request MSFS transponder data", Q_FUNC_INFO,
"SimConnect_RequestDataOnSimObject");
559 void CSimulatorFsxCommon::onSimStopped()
564 m_simSimulating =
false;
565 m_simulatingChangedTs = QDateTime::currentMSecsSinceEpoch();
569 void CSimulatorFsxCommon::onSimFrame()
572 QPointer<CSimulatorFsxCommon> myself(
this);
575 if (!myself) {
return; }
576 myself->updateRemoteAircraft();
580 void CSimulatorFsxCommon::onSimExit()
585 m_simulatingChangedTs = QDateTime::currentMSecsSinceEpoch();
589 QPointer<CSimulatorFsxCommon> myself(
this);
591 if (!myself) {
return; }
598 const SIMCONNECT_DATA_REQUEST_ID
id = m_requestIdSimObjAircraft++;
599 if (
id > RequestSimObjAircraftEnd) { m_requestIdSimObjAircraft = RequestSimObjAircraftStart; }
605 const SIMCONNECT_DATA_REQUEST_ID
id = m_requestIdSimObjTerrainProbe++;
606 if (
id > RequestSimObjTerrainProbeEnd) { m_requestIdSimObjTerrainProbe = RequestSimObjTerrainProbeStart; }
612 const SIMCONNECT_OBJECT_ID objectId = simObject.
getObjectId();
615 "Release control", Q_FUNC_INFO,
"SimConnect_AIReleaseControl");
618 SIMCONNECT_GROUP_PRIORITY_HIGHEST,
619 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
620 simObject,
"EventFreezeLatLng", Q_FUNC_INFO,
"SimConnect_TransmitClientEvent");
623 SIMCONNECT_GROUP_PRIORITY_HIGHEST,
624 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
625 simObject,
"EventFreezeAlt", Q_FUNC_INFO,
"SimConnect_TransmitClientEvent");
628 SIMCONNECT_GROUP_PRIORITY_HIGHEST,
629 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
630 simObject,
"EventFreezeAtt", Q_FUNC_INFO,
"SimConnect_TransmitClientEvent");
632 return isOk(hr1, hr2, hr3, hr4);
667 if (m_traceSendId) {
return false; }
669 const qint64 ts = QDateTime::currentMSecsSinceEpoch();
670 const qint64 traceUntil = traceTimeMs + ts;
671 if (traceUntil <= m_traceAutoUntilTs) {
return false; }
672 m_traceAutoUntilTs = traceUntil;
674 static const QString format(
"hh:mm:ss.zzz");
675 const QString untilString = QDateTime::fromMSecsSinceEpoch(traceUntil).toString(format);
676 CLogMessage(
this).
info(u
"Triggered FSX/P3D auto trace until %1") << untilString;
677 const QPointer<CSimulatorFsxCommon> myself(
this);
680 if (!myself) {
return; }
681 if (m_traceAutoUntilTs > QDateTime::currentMSecsSinceEpoch()) {
return; }
682 if (m_traceAutoUntilTs < 0) {
return; }
684 m_traceAutoUntilTs = -1;
698 const qint64 ts = QDateTime::currentMSecsSinceEpoch();
705 if (simulatorOwnAircraft.
pitchDeg < -90.0 || simulatorOwnAircraft.
pitchDeg >= 90.0)
720 CAircraftSituation::FromProvider);
723 CAltitude::PressureAltitude, CLengthUnit::m()));
727 {
dtb(simulatorOwnAircraft.
simOnGround) ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround,
728 COnGroundInfo::OutOnGroundOwnAircraft });
747 for (
int index = 0; index < simulatorOwnAircraft.
numberOfEngines; ++index)
778 const bool com1Test =
dtb(simulatorOwnAircraft.
comTest1);
780 const int com1Status =
783 com1.setTransmitEnabled(com1Status == 0 && com1Transmit);
784 com1.setReceiveEnabled(com1Status == 0 && (comReceiveAll || com1Transmit));
786 const bool changedCom1Active =
787 myAircraft.getCom1System().getFrequencyActive() != com1.getFrequencyActive() &&
788 com1.getFrequencyActive() != m_lastCom1Active;
789 const bool changedCom1Standby =
790 myAircraft.getCom1System().getFrequencyStandby() != com1.getFrequencyStandby() &&
791 com1.getFrequencyStandby() != m_lastCom1Standby;
794 if (!changedCom1Active) { com1.setFrequencyActive(myAircraft.getCom1System().getFrequencyActive()); }
795 else { m_lastCom1Active.
setNull(); }
797 if (!changedCom1Standby) { com1.setFrequencyStandby(myAircraft.getCom1System().getFrequencyStandby()); }
798 else { m_lastCom1Standby.
setNull(); }
800 const bool changedCom1 = myAircraft.getCom1System() != com1;
807 const bool com2Test =
dtb(simulatorOwnAircraft.
comTest2);
809 const int com2Status =
812 com2.setTransmitEnabled(com2Status == 0 && com2Transmit);
813 com2.setReceiveEnabled(com2Status == 0 && (comReceiveAll || com2Transmit));
814 const bool changedCom2Active =
815 myAircraft.getCom2System().getFrequencyActive() != com2.getFrequencyActive() &&
816 com2.getFrequencyActive() != m_lastCom2Active;
817 const bool changedCom2Standby =
818 myAircraft.getCom2System().getFrequencyStandby() != com2.getFrequencyStandby() &&
819 com2.getFrequencyStandby() != m_lastCom2Standby;
822 if (!changedCom2Active) { com2.setFrequencyActive(myAircraft.getCom2System().getFrequencyActive()); }
823 else { m_lastCom2Active.
setNull(); }
825 if (!changedCom2Standby) { com2.setFrequencyStandby(myAircraft.getCom2System().getFrequencyStandby()); }
826 else { m_lastCom2Standby.
setNull(); }
828 const bool changedCom2 = myAircraft.getCom2System() != com2;
834 transponder.setTransponderCode(qRound(simulatorOwnAircraft.
transponderCode));
840 const bool changedXpr = (myAircraft.getTransponderCode() != transponder.getTransponderCode());
842 if (changedCom1 || changedCom2 || changedXpr)
856 this->physicallyInitAITerrainProbes(position, 2);
862 QString::number(m_sbDataReceived) :
863 QStringLiteral(
"disabled"));
878 void CSimulatorFsxCommon::triggerUpdateRemoteAircraftFromSimulator(
const CSimConnectObject &simObject,
879 const DataDefinitionPosData &remoteAircraftData)
882 QPointer<CSimulatorFsxCommon> myself(
this);
884 if (!myself) {
return; }
885 myself->updateRemoteAircraftFromSimulator(simObject, remoteAircraftData);
889 void CSimulatorFsxCommon::triggerUpdateRemoteAircraftFromSimulator(
890 const CSimConnectObject &simObject,
const DataDefinitionRemoteAircraftModel &remoteAircraftModel)
893 QPointer<CSimulatorFsxCommon> myself(
this);
895 if (!myself) {
return; }
896 myself->updateRemoteAircraftFromSimulator(simObject, remoteAircraftModel);
900 void CSimulatorFsxCommon::updateRemoteAircraftFromSimulator(
const CSimConnectObject &simObject,
901 const DataDefinitionPosData &remoteAircraftData)
906 const CCallsign cs(simObject.getCallsign());
908 const bool moving = lastSituation.
isMoving();
909 const bool onGround = remoteAircraftData.isOnGround();
914 CElevationPlane(remoteAircraftData.latitudeDeg, remoteAircraftData.longitudeDeg,
915 remoteAircraftData.elevationFt, CElevationPlane::singlePointRadius());
916 if (remoteAircraftData.aboveGroundFt() < 250)
918 const CLength cg(remoteAircraftData.cgToGroundFt, CLengthUnit::ft());
926 const CAltitude alt(remoteAircraftData.altitudeFt, CAltitude::MeanSeaLevel, CAltitude::TrueAltitude,
934 if (moving && remoteAircraftData.aboveGroundFt() <= 100.0)
937 if (simObject.getSimDataPeriod() != SIMCONNECT_PERIOD_VISUAL_FRAME)
939 this->requestPositionDataForSimObject(simObject, SIMCONNECT_PERIOD_VISUAL_FRAME);
945 if (simObject.getSimDataPeriod() != SIMCONNECT_PERIOD_SECOND)
947 this->requestPositionDataForSimObject(simObject, SIMCONNECT_PERIOD_SECOND);
953 CSimulatorFsxCommon::updateRemoteAircraftFromSimulator(
const CSimConnectObject &simObject,
954 const DataDefinitionRemoteAircraftModel &remoteAircraftModel)
956 const CCallsign cs(simObject.getCallsign());
959 if (so.isPendingRemoved()) {
return; }
961 const QString modelString(remoteAircraftModel.title);
962 const CLength cg(remoteAircraftModel.cgToGroundFt, CLengthUnit::ft());
963 so.setAircraftCG(cg);
964 so.setAircraftModelString(modelString);
972 void CSimulatorFsxCommon::updateProbeFromSimulator(
const CCallsign &callsign,
973 const DataDefinitionPosData &remoteAircraftData)
975 const CElevationPlane elevation(remoteAircraftData.latitudeDeg, remoteAircraftData.longitudeDeg,
976 remoteAircraftData.elevationFt, CElevationPlane::singlePointRadius());
980 void CSimulatorFsxCommon::updateOwnAircraftFromSimulator(
const DataDefinitionClientAreaSb &sbDataArea)
985 if (m_logSbOffsets) {
CLogMessage(
this).
info(u
"SB from sim: " % sbDataArea.toQString()); }
989 if (!sbDataArea.isIdent())
991 newMode = sbDataArea.isStandby() ? CTransponder::StateStandby : CTransponder::ModeC;
994 const bool changed = (myAircraft.getTransponderMode() != newMode);
995 if (!changed) {
return; }
998 this->
updateCockpit(myAircraft.getCom1System(), myAircraft.getCom2System(), xpdr, this->identifier());
1005 const bool changed = (myAircraft.getTransponderMode() != xpdrMode);
1006 if (!changed) {
return; }
1009 this->
updateCockpit(myAircraft.getCom1System(), myAircraft.getCom2System(), myXpdr, this->identifier());
1012 void CSimulatorFsxCommon::updateMSFSTransponderMode(
const DataDefinitionMSFSTransponderMode transponderMode)
1014 auto mode = CTransponder::StateIdent;
1015 if (!transponderMode.ident)
1017 qRound(transponderMode.transponderMode) >= 3 ? mode = CTransponder::ModeC :
1018 mode = CTransponder::StateStandby;
1020 this->updateTransponderMode(mode);
1023 bool CSimulatorFsxCommon::simulatorReportedObjectAdded(
DWORD objectId)
1027 const CCallsign callsign(simObject.getCallsign());
1028 if (!simObject.hasValidRequestAndObjectId() || callsign.isEmpty()) {
return false; }
1032 const QPointer<CSimulatorFsxCommon> myself(
this);
1037 this->verifyAddedRemoteAircraft(verifyAircraft);
1042 void CSimulatorFsxCommon::verifyAddedRemoteAircraft(
const CSimulatedAircraft &remoteAircraftIn)
1047 this->verifyAddedTerrainProbe(remoteAircraftIn);
1057 if (callsign.isEmpty())
1059 msg =
CLogMessage(
this).
error(u
"Cannot confirm AI object, empty callsign");
1067 if (aircraftStillInRange)
1070 u
"Callsign '%1' removed in meantime from AI objects, but still in range")
1071 << callsign.toQString();
1075 this->removeFromAddPendingAndAddAgainAircraft(callsign);
1076 msg =
CLogMessage(
this).
info(u
"Callsign '%1' removed in meantime and no longer in range")
1077 << callsign.toQString();
1083 remoteAircraft = simObject.getAircraft();
1085 if (!simObject.hasValidRequestAndObjectId() || simObject.isPendingRemoved())
1088 << callsign.
toQString() << simObject.getObjectId();
1104 Q_ASSERT_X(simObject.isPendingAdded(), Q_FUNC_INFO,
"Already confirmed, this should be the only place");
1105 simObject.setConfirmedAdded(
true);
1108 this->requestPositionDataForSimObject(simObject);
1109 this->requestLightsForSimObject(simObject);
1110 this->requestModelInfoForSimObject(simObject);
1112 this->removeFromAddPendingAndAddAgainAircraft(callsign);
1116 static const QString debugMsg(
"CS: '%1' model: '%2' verified, request/object id: %3 %4");
1120 debugMsg.arg(callsign.toQString(), remoteAircraft.
getModelString())
1121 .arg(simObject.getRequestId())
1122 .arg(simObject.getObjectId()));
1125 this->sendRemoteAircraftAtcDataToSimulator(simObject);
1131 u
"Verified aircraft '%1' model '%2', request/object id: %3 %4 was already marked rendered")
1132 << callsign.asString() << remoteAircraft.
getModelString() << simObject.getRequestId()
1133 << simObject.getObjectId();
1136 if (simObject.isConfirmedAdded() && simObject.getType() == CSimConnectObject::AircraftSimulatedObject)
1140 << simObject.getTypeAsString();
1142 simObject.decreaseAddingExceptions();
1150 CLogMessage::preformatted(msg);
1155 if (!m_addPendingAircraft.isEmpty()) { this->addPendingAircraftAfterAdded(); }
1158 void CSimulatorFsxCommon::addingAircraftFailed(
const CSimConnectObject &simObject)
1160 if (CBuildConfig::isLocalDeveloperDebugBuild())
1162 Q_ASSERT_X(simObject.isAircraft(), Q_FUNC_INFO,
"Need aircraft");
1164 if (!simObject.isAircraft()) {
return; }
1168 this->removeFromAddPendingAndAddAgainAircraft(simObject.getCallsign());
1171 << simObject.getAircraftModelString() << simObject.getAircraft().toQString(
true);
1173 const bool verifiedAircraft = this->verifyFailedAircraftInfo(simObject, verifyMsg);
1174 if (!verifyMsg.
isEmpty()) { CLogMessage::preformatted(verifyMsg); }
1176 CSimConnectObject simObjAddAgain(simObject);
1177 simObjAddAgain.increaseAddingExceptions();
1178 if (!simObject.hasCallsign())
1184 if (!verifiedAircraft || simObjAddAgain.getAddingExceptions() > ThresholdAddException)
1188 CLogMessage(
this).
warning(u
"Model '%1' %2 failed %3 time(s) before and will be disabled")
1189 << simObjAddAgain.getAircraftModelString() << simObjAddAgain.toQString()
1190 << simObjAddAgain.getAddingExceptions() :
1192 << simObjAddAgain.getAircraftModelString() << simObjAddAgain.toQString();
1200 << simObject.getAircraftModelString() << simObject.getAircraft().toQString(
true);
1201 QPointer<CSimulatorFsxCommon> myself(
this);
1203 if (!myself) {
return; }
1205 m_addPendingAircraft.
insert(simObjAddAgain,
true);
1210 bool CSimulatorFsxCommon::verifyFailedAircraftInfo(
const CSimConnectObject &simObject,
1217 bool canBeUsed =
true;
1223 bool parsed =
false;
1225 CAircraftCfgParser::performParsingOfSingleFile(model.
getFileName(), parsed, messages);
1237 CStatusMessage(
this).warning(u
"Model '%1' no longer in re-parsed file '%2'. Models are: %3.")
1263 bool CSimulatorFsxCommon::logVerifyFailedAircraftInfo(
const CSimConnectObject &simObject)
const
1266 const bool r = verifyFailedAircraftInfo(simObject, m);
1267 if (!m.
isEmpty()) { CLogMessage::preformatted(m); }
1271 void CSimulatorFsxCommon::verifyAddedTerrainProbe(
const CSimulatedAircraft &remoteAircraftIn)
1273 bool verified =
false;
1279 simObject.setConfirmedAdded(
true);
1280 simObject.resetTimestampToNow();
1281 cs = simObject.getCallsign();
1283 << simObject.getCallsignAsString() << simObject.getAircraftModelString() << simObject.toQString();
1298 if (!m_addPendingAircraft.isEmpty()) { this->addPendingAircraftAfterAdded(); }
1301 void CSimulatorFsxCommon::timerBasedObjectAddOrRemove()
1303 this->addPendingAircraft(AddByTimer);
1304 if (!this->
isTestMode()) { this->physicallyRemoveAircraftNotInProvider(); }
1307 void CSimulatorFsxCommon::addPendingAircraftAfterAdded()
1309 this->addPendingAircraft(AddAfterAdded);
1312 void CSimulatorFsxCommon::addPendingAircraft(AircraftAddMode mode)
1314 if (m_addPendingAircraft.isEmpty()) {
return; }
1319 for (
const CSimConnectObject &pendingSimObj : std::as_const(m_addPendingAircraft))
1321 SWIFT_VERIFY_X(pendingSimObj.hasCallsign(), Q_FUNC_INFO,
"missing callsign");
1322 if (!pendingSimObj.hasCallsign()) {
continue; }
1323 if (pendingSimObj.isTerrainProbe() || aircraftCallsignsInRange.contains(pendingSimObj.getCallsign()))
1325 toBeAddedAircraft.
push_back(pendingSimObj.getAircraft());
1327 else { toBeRemovedCallsigns.
push_back(pendingSimObj.getCallsign()); }
1335 if (!toBeAddedAircraft.
isEmpty())
1337 const CSimConnectObject oldestSimObject = m_addPendingAircraft.
getOldestObject();
1341 const QPointer<CSimulatorFsxCommon> myself(
this);
1343 if (!myself) {
return; }
1345 this->physicallyAddRemoteAircraftImpl(nextPendingAircraft, mode, oldestSimObject);
1356 CSimConnectObject CSimulatorFsxCommon::removeFromAddPendingAndAddAgainAircraft(
const CCallsign &callsign)
1358 CSimConnectObject simObjectOld;
1359 if (callsign.
isEmpty()) {
return simObjectOld; }
1362 if (m_addPendingAircraft.contains(callsign))
1364 simObjectOld = m_addPendingAircraft[callsign];
1365 m_addPendingAircraft.remove(callsign);
1367 return simObjectOld;
1370 bool CSimulatorFsxCommon::simulatorReportedObjectRemoved(
DWORD objectID)
1374 if (!simObject.hasValidRequestAndObjectId()) {
return false; }
1376 const CCallsign callsign(simObject.getCallsign());
1377 Q_ASSERT_X(!callsign.
isEmpty(), Q_FUNC_INFO,
"Missing callsign for removed object");
1379 if (simObject.isPendingRemoved())
1393 if (!simObject.getAircraftModelString().isEmpty() &&
1394 simObject.getAddingDirectlyRemoved() < ThresholdAddedAndDirectlyRemoved)
1396 simObject.increaseAddingDirectlyRemoved();
1397 m_addPendingAircraft.
insert(simObject,
true);
1403 msg =
CLogMessage(
this).
warning(u
"Aircraft removed, '%1' '%2' object id '%3' out of reality bubble or "
1404 u
"other reason. Interpolator: '%4'")
1405 << callsign.
toQString() << simObject.getAircraftModelString() << objectID
1408 else if (simObject.getAddingDirectlyRemoved() < ThresholdAddedAndDirectlyRemoved)
1412 u
"Aircraft removed again multiple times and will be disabled, '%1' '%2' object id '%3'")
1413 << callsign.
toQString() << simObject.getAircraftModelString() << objectID;
1421 u
"Removed '%1' from simulator, but was not initiated by us (swift): %1 '%2' object id %3")
1422 << callsign.
toQString() << simObject.getAircraftModelString() << objectID;
1426 this->logVerifyFailedAircraftInfo(simObject);
1434 const bool removedAny = (c > 0);
1443 QPointer<CSimulatorFsxCommon> myself(
this);
1445 if (!myself) {
return; }
1447 myself->physicallyAddRemoteAircraftImpl(aircraftAddAgain, AddedAfterRemoved);
1453 bool CSimulatorFsxCommon::setSimConnectObjectId(
DWORD requestId,
DWORD objectId)
1486 const bool trace = parser.
toBool(2);
1487 this->setTraceSendId(trace);
1488 CLogMessage(
this, CLogCategories::cmdLine()).
info(u
"Tracing %1 driver sendIds is '%2'")
1496 const bool on = parser.
toBool(2);
1505 const bool on = parser.
toBool(2);
1506 m_logSbOffsets = on;
1511 return CSimulatorFsCommon::parseDetails(parser);
1516 if (CSimpleCommandParser::registered(
"swift::simplugin::fsxcommon::CSimulatorFsxCommon::CSimulatorFsxCommon"))
1520 CSimpleCommandParser::registerCommand({
".drv",
"alias: .driver .plugin" });
1521 CSimpleCommandParser::registerCommand({
".drv sendid on|off",
"Trace simConnect sendId on|off" });
1522 CSimpleCommandParser::registerCommand({
".drv sboffsets on|off",
"SB offsets via simConnect on|off" });
1523 CSimpleCommandParser::registerCommand({
".drv sblog on|off",
"SB offsets logging on|off" });
1533 const QString &CSimulatorFsxCommon::modeToString(CSimulatorFsxCommon::AircraftAddMode mode)
1535 static const QString e(
"external call");
1536 static const QString pt(
"add pending by timer");
1537 static const QString oa(
"add pending after object added");
1538 static const QString ar(
"add again after removed");
1539 static const QString dontKnow(
"???");
1543 case ExternalCall:
return e;
1544 case AddByTimer:
return pt;
1545 case AddAfterAdded:
return oa;
1546 case AddedAfterRemoved:
return ar;
1552 void CSimulatorFsxCommon::dispatch()
1558 m_dispatchReceiveIdLast = SIMCONNECT_RECV_ID_NULL;
1560 const qint64 start = QDateTime::currentMSecsSinceEpoch();
1566 const qint64
end = QDateTime::currentMSecsSinceEpoch();
1567 m_dispatchTimeMs =
end - start;
1568 if (m_dispatchMaxTimeMs < m_dispatchTimeMs)
1570 m_dispatchMaxTimeMs = m_dispatchTimeMs;
1571 m_dispatchReceiveIdMaxTime = m_dispatchReceiveIdLast;
1572 m_dispatchRequestIdMaxTime = m_dispatchRequestIdLast;
1581 const bool disconnectedOrNotSimulating =
1586 if (m_dispatchErrors == 2)
1591 QStringLiteral(u
"%1: Dispatch error, sim.status: %2")
1594 disconnectedOrNotSimulating ? CStatusMessage::SeverityWarning : CStatusMessage::SeverityError, msg);
1596 else if (m_dispatchErrors > 5)
1600 QStringLiteral(u
"%1: Multiple dispatch errors, disconnecting. Sim.status: %2")
1603 disconnectedOrNotSimulating ? CStatusMessage::SeverityWarning : CStatusMessage::SeverityError, msg);
1608 m_dispatchErrors = 0;
1611 bool CSimulatorFsxCommon::physicallyAddRemoteAircraftImpl(
const CSimulatedAircraft &newRemoteAircraft,
1612 CSimulatorFsxCommon::AircraftAddMode addMode,
1613 const CSimConnectObject &correspondingSimObject)
1619 Q_ASSERT_X(CThreadUtils::isInThisThread(
this), Q_FUNC_INFO,
"thread");
1620 Q_ASSERT_X(!callsign.
isEmpty(), Q_FUNC_INFO,
"empty callsign");
1621 Q_ASSERT_X(newRemoteAircraft.
hasModelString(), Q_FUNC_INFO,
"missing model string");
1624 m_simObjectTimer.start(AddPendingAircraftIntervalMs);
1627 const CSimConnectObjects outdatedAdded =
1629 if (!outdatedAdded.isEmpty())
1631 const CCallsignSet callsigns = outdatedAdded.getAllCallsigns(
false);
1636 static const QString msgText(
"%1 outdated adding, %2");
1637 for (
const CSimConnectObject &simObjOutdated : outdatedAdded)
1640 msgText.arg(simObjOutdated.getCallsign().asString(), simObjOutdated.toQString()));
1649 bool canAdd = this->
isSimulating() && !hasPendingAdded;
1652 "There must be only 0..1 pending objects");
1655 this->
debugLogMessage(Q_FUNC_INFO, QStringLiteral(
"CS: '%1' mode: '%2' model: '%3'")
1659 Q_FUNC_INFO, QStringLiteral(
"CS: '%1' pending callsigns: '%2', pending objects: '%3'")
1670 const QString newModelString(newRemoteAircraft.
getModelString());
1671 const QString simObjModelString(simObject.getAircraftModelString());
1672 const bool sameModel =
1673 (simObjModelString ==
1684 const bool rendered = simObject.isConfirmedAdded() && simObject.isPending();
1694 QStringLiteral(
"CS: '%1' re-added changed model '%2', will be added again")
1702 if (canAdd && situation.isPositionOrAltitudeNull())
1706 if (situations.isEmpty())
1713 CLogMessage(
this).
warning(u
"Invalid aircraft situation for new aircraft '%1', use closest situation")
1715 situation = situations.findClosestTimeDistanceAdjusted(QDateTime::currentMSecsSinceEpoch());
1716 Q_ASSERT_X(!situation.isPositionOrAltitudeNull(), Q_FUNC_INFO,
"Invalid situation for new aircraft");
1720 canAdd = situation.isPositionOrAltitudeNull();
1721 if (CBuildConfig::isLocalDeveloperDebugBuild())
1731 CSimConnectObject &addPendingObj = m_addPendingAircraft[newRemoteAircraft.
getCallsign()];
1732 addPendingObj.setAircraft(newRemoteAircraft);
1733 addPendingObj.resetTimestampToNow();
1738 const CSimConnectObject removedPendingObj = this->removeFromAddPendingAndAddAgainAircraft(callsign);
1753 bool adding =
false;
1754 const SIMCONNECT_DATA_REQUEST_ID requestId =
1761 const CSimConnectObject dummyObject = CSimConnectObject(
1764 dummyObject.getInterpolation(QDateTime::currentMSecsSinceEpoch(), setup, 0);
1775 const SIMCONNECT_DATA_INITPOSITION initialPosition =
1781 this->
debugLogMessage(Q_FUNC_INFO, QStringLiteral(
"CS: '%1' model: '%2' request: %3, init pos: %4")
1784 .arg(fsxPositionToString(initialPosition)));
1787 const QByteArray modelStringBa =
toFsxChar(modelString);
1794 hr = SimConnect_AICreateSimulatedObject(
m_hSimConnect, modelStringBa.constData(), initialPosition,
1796 type = CSimConnectObject::TerrainProbe;
1801 correspondingSimObject.getAddingExceptions() > 0 &&
1802 correspondingSimObject.getType() == CSimConnectObject::AircraftNonAtc)
1805 u
"Model '%1' for '%2' failed %1 time(s) before, using AICreateSimulatedObject now")
1807 hr = SimConnect_AICreateSimulatedObject(
m_hSimConnect, modelStringBa.constData(), initialPosition,
1809 type = CSimConnectObject::AircraftSimulatedObject;
1813 hr = SimConnect_AICreateNonATCAircraft(
m_hSimConnect, modelStringBa.constData(), csBa.constData(),
1814 initialPosition, requestId);
1815 type = CSimConnectObject::AircraftNonAtc;
1819 if (!underflowStatus.
isEmpty())
1829 CLogMessage::preformatted(msg);
1836 const CSimConnectObject simObject =
1837 this->insertNewSimConnectObject(newRemoteAircraft, requestId, type, removedPendingObj);
1838 this->traceSendId(simObject, Q_FUNC_INFO,
1839 QStringLiteral(
"mode: %1").arg(CSimulatorFsxCommon::modeToString(addMode)),
true);
1845 bool CSimulatorFsxCommon::physicallyAddAITerrainProbe(
const ICoordinateGeodetic &coordinate,
int number)
1847 if (coordinate.
isNull()) {
return false; }
1849 Q_ASSERT_X(CThreadUtils::isInThisThread(
this), Q_FUNC_INFO,
"thread");
1857 static const QString modelString(
"swiftTerrainProbe0");
1858 static const QString pseudoCallsign(
"PROBE%1");
1859 static const CCountry ctry(
"SW",
"SWIFT");
1860 static const CAirlineIcaoCode swiftAirline(
"SWI",
"swift probe", ctry,
"SWIFT",
false,
false);
1861 static const CLivery swiftLivery(CLivery::getStandardCode(swiftAirline), swiftAirline,
"swift probe");
1863 const CCallsign cs(pseudoCallsign.arg(number));
1864 const CAircraftModel model(modelString, CAircraftModel::TypeTerrainProbe, QStringLiteral(
"swift terrain probe"),
1865 CAircraftIcaoCode::unassignedIcao(), swiftLivery);
1867 situation.setAltitude(terrainProbeAltitude());
1868 situation.setZeroPBH();
1870 return this->physicallyAddRemoteAircraftImpl(pseudoAircraft, ExternalCall);
1873 int CSimulatorFsxCommon::physicallyInitAITerrainProbes(
const ICoordinateGeodetic &coordinate,
int number)
1875 if (number < 1) {
return 0; }
1881 for (
int n = 0; n < number; ++n)
1883 if (this->physicallyAddAITerrainProbe(coordinate, n)) { c++; }
1894 Q_ASSERT_X(CThreadUtils::isInThisThread(
this), Q_FUNC_INFO,
"wrong thread");
1895 if (callsign.
isEmpty()) {
return false; }
1898 this->removeFromAddPendingAndAddAgainAircraft(callsign);
1907 m_addPendingAircraft.remove(callsign);
1914 CLogMessage(
this).
warning(u
"'%1' requested to be removed, but pending added (%2) / or pending lights(%3). "
1915 u
"Object will be removed again: %4")
1916 << callsign.
asString() << boolToYesNo(pendingAdded) << boolToYesNo(stillWaitingForLights)
1919 QPointer<CSimulatorFsxCommon> myself(
this);
1921 if (!myself) {
return; }
1923 myself->physicallyRemoveRemoteAircraft(callsign);
1929 this->stopRequestingDataForSimObject(simObject);
1935 this->
debugLogMessage(Q_FUNC_INFO, QStringLiteral(
"CS: '%1' request/object id: %2/%3")
1942 const SIMCONNECT_DATA_REQUEST_ID requestId = simObject.
getRequestId(CSimConnectDefinitions::SimObjectRemove);
1945 const HRESULT result = SimConnect_AIRemoveObject(
1949 if (this->
isTracingSendId()) { this->traceSendId(simObject, Q_FUNC_INFO); }
1963 this->physicallyRemoveAircraftNotInProviderAsync();
1966 return CSimulatorPluginCommon::physicallyRemoveRemoteAircraft(callsign);
1973 m_addPendingAircraft.clear();
1984 CSimulatorFsCommon::physicallyRemoveAllRemoteAircraft();
1988 HRESULT CSimulatorFsxCommon::initEvents()
1990 HRESULT hr =
s_ok();
1992 hr += SimConnect_SubscribeToSystemEvent(
m_hSimConnect, SystemEventSimStatus,
"Sim");
1993 hr += SimConnect_SubscribeToSystemEvent(
m_hSimConnect, SystemEventObjectAdded,
"ObjectAdded");
1994 hr += SimConnect_SubscribeToSystemEvent(
m_hSimConnect, SystemEventObjectRemoved,
"ObjectRemoved");
1995 hr += SimConnect_SubscribeToSystemEvent(
m_hSimConnect, SystemEventFrame,
"Frame");
1996 hr += SimConnect_SubscribeToSystemEvent(
m_hSimConnect, SystemEventPause,
"Pause");
1997 hr += SimConnect_SubscribeToSystemEvent(
m_hSimConnect, SystemEventFlightLoaded,
"FlightLoaded");
2000 CLogMessage(
this).
error(u
"FSX plugin error: %1") <<
"SimConnect_SubscribeToSystemEvent failed";
2007 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventPauseToggle,
"PAUSE_TOGGLE");
2008 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, SystemEventSlewToggle,
"SLEW_TOGGLE");
2009 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventFreezeLatLng,
2010 "FREEZE_LATITUDE_LONGITUDE_SET");
2011 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventFreezeAlt,
2012 "FREEZE_ALTITUDE_SET");
2013 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventFreezeAtt,
2014 "FREEZE_ATTITUDE_SET");
2015 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventSetCom1Active,
"COM_RADIO_SET");
2016 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventSetCom1Standby,
"COM_STBY_RADIO_SET");
2017 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventSetCom2Active,
"COM2_RADIO_SET");
2018 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventSetCom2Standby,
"COM2_STBY_RADIO_SET");
2019 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventSetTransponderCode,
"XPNDR_SET");
2021 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventSetTimeZuluYear,
"ZULU_YEAR_SET");
2022 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventSetTimeZuluDay,
"ZULU_DAY_SET");
2023 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventSetTimeZuluHours,
"ZULU_HOURS_SET");
2024 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventSetTimeZuluMinutes,
"ZULU_MINUTES_SET");
2026 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventLandingLightsOff,
"LANDING_LIGHTS_OFF");
2027 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventLandinglightsOn,
"LANDING_LIGHTS_ON");
2028 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventLandingLightsSet,
"LANDING_LIGHTS_SET");
2029 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventLandingLightsToggle,
"LANDING_LIGHTS_TOGGLE");
2030 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventPanelLightsOff,
"PANEL_LIGHTS_OFF");
2031 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventPanelLightsOn,
"PANEL_LIGHTS_ON");
2032 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventPanelLightsSet,
"PANEL_LIGHTS_SET");
2033 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventStrobesOff,
"STROBES_OFF");
2034 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventStrobesOn,
"STROBES_ON");
2035 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventStrobesSet,
"STROBES_SET");
2036 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventStrobesToggle,
"STROBES_TOGGLE");
2037 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventToggleBeaconLights,
"TOGGLE_BEACON_LIGHTS");
2038 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventToggleCabinLights,
"TOGGLE_CABIN_LIGHTS");
2039 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventToggleLogoLights,
"TOGGLE_LOGO_LIGHTS");
2040 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventToggleNavLights,
"TOGGLE_NAV_LIGHTS");
2041 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventToggleRecognitionLights,
2042 "TOGGLE_RECOGNITION_LIGHTS");
2043 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventToggleTaxiLights,
"TOGGLE_TAXI_LIGHTS");
2044 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventToggleWingLights,
"TOGGLE_WING_LIGHTS");
2046 hr += SimConnect_MapClientEventToSimEvent(
m_hSimConnect, EventFlapsSet,
"FLAPS_SET");
2050 CLogMessage(
this).
error(u
"FSX plugin error: %1") <<
"SimConnect_MapClientEventToSimEvent failed";
2055 SIMCONNECT_DATA_REQUEST_ID requestId =
2056 static_cast<SIMCONNECT_DATA_REQUEST_ID
>(CSimConnectDefinitions::RequestFacility);
2057 hr += SimConnect_SubscribeToFacilities(
m_hSimConnect, SIMCONNECT_FACILITY_LIST_TYPE_AIRPORT, requestId);
2060 CLogMessage(
this).
error(u
"FSX plugin error: %1") <<
"SimConnect_SubscribeToFacilities failed";
2066 HRESULT CSimulatorFsxCommon::initDataDefinitionsWhenConnected()
2072 HRESULT CSimulatorFsxCommon::initWhenConnected()
2076 HRESULT hr = this->initEvents();
2084 hr += this->initDataDefinitionsWhenConnected();
2087 CLogMessage(
this).
error(u
"FSX plugin: initDataDefinitionsWhenConnected failed");
2094 void CSimulatorFsxCommon::updateRemoteAircraft()
2096 static_assert(
sizeof(DataDefinitionRemoteAircraftPartsWithoutLights) ==
sizeof(
double) * 10,
2097 "DataDefinitionRemoteAircraftPartsWithoutLights has an incorrect size.");
2098 Q_ASSERT_X(CThreadUtils::isInThisThread(
this), Q_FUNC_INFO,
"thread");
2102 if (remoteAircraftNo < 1)
2109 const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch();
2120 uint32_t simObjectNumber = 0;
2123 for (
const CSimConnectObject &simObject : simObjects)
2126 if (!simObject.isReadyToSend()) {
continue; }
2127 if (!simObject.hasCurrentLightsInSimulator()) {
continue; }
2129 const CCallsign callsign(simObject.getCallsign());
2130 const bool hasCs = !callsign.
isEmpty();
2131 const bool hasValidIds = simObject.hasValidRequestAndObjectId();
2134 if (!hasCs || !hasValidIds) {
continue; }
2135 const DWORD objectId = simObject.getObjectId();
2145 const CInterpolationResult result = simObject.getInterpolation(currentTimestamp, setup, simObjectNumber++);
2154 const CLength relativeAltitude =
2156 const double altitudeDeltaWeight =
2157 2 - qBound(3000.0, relativeAltitude.
abs().
value(CLengthUnit::ft()), 6000.0) / 3000;
2165 static_cast<SIMCONNECT_OBJECT_ID
>(objectId), 0, 0,
2166 sizeof(SIMCONNECT_DATA_INITPOSITION), &position),
2167 traceSendId, simObject,
"Failed to set position", Q_FUNC_INFO,
"SimConnect_SetDataOnSimObject");
2181 const bool updatedParts = this->updateRemoteAircraftParts(simObject, result, forceUpdate);
2182 Q_UNUSED(updatedParts)
2190 bool CSimulatorFsxCommon::updateRemoteAircraftParts(
const CSimConnectObject &simObject,
2193 if (!simObject.hasValidRequestAndObjectId()) {
return false; }
2194 if (!simObject.isConfirmedAdded()) {
return false; }
2197 if (parts.
isNull()) {
return false; }
2203 const CCallsign cs = simObject.getCallsign();
2209 const bool ok = this->sendRemoteAircraftPartsToSimulator(simObject, parts);
2214 bool CSimulatorFsxCommon::sendRemoteAircraftPartsToSimulator(
const CSimConnectObject &simObject,
2218 if (!simObject.isReadyToSend()) {
return false; }
2220 const DWORD objectId = simObject.getObjectId();
2223 DataDefinitionRemoteAircraftPartsWithoutLights ddRemoteAircraftPartsWithoutLights(parts);
2227 const bool simObjectAircraftType = simObject.isAircraftSimulatedObject();
2229 simObjectAircraftType ?
2232 SimConnect_SetDataOnSimObject(
2233 m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPartsWithoutLights,
2234 static_cast<SIMCONNECT_OBJECT_ID
>(objectId), SIMCONNECT_DATA_SET_FLAG_DEFAULT, 0,
2235 sizeof(DataDefinitionRemoteAircraftPartsWithoutLights), &ddRemoteAircraftPartsWithoutLights),
2236 traceId, simObject,
"Failed so set parts", Q_FUNC_INFO,
2237 "SimConnect_SetDataOnSimObject::ddRemoteAircraftPartsWithoutLights");
2243 SimConnect_TransmitClientEvent(
m_hSimConnect, objectId, EventFlapsSet, flapsDw,
2244 SIMCONNECT_GROUP_PRIORITY_HIGHEST,
2245 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
2246 traceId, simObject,
"Failed so set flaps", Q_FUNC_INFO,
"SimConnect_TransmitClientEvent::EventFlapsSet");
2250 SimConnect_TransmitClientEvent(
m_hSimConnect, objectId, EventLandingLightsSet,
2251 lights.
isLandingOn() ? 1.0 : 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST,
2252 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
2253 traceId, simObject,
"Failed so set landing lights", Q_FUNC_INFO,
2254 "SimConnect_TransmitClientEvent::EventLandingLightsSet");
2259 SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
2260 traceId, simObject,
"Failed to set strobe lights", Q_FUNC_INFO,
2261 "SimConnect_TransmitClientEvent::EventStrobesSet");
2266 this->sendToggledLightsToSimulator(simObject, lights);
2269 return isOk(hr1, hr2, hr3, hr4);
2272 bool CSimulatorFsxCommon::sendRemoteAircraftAtcDataToSimulator(
const CSimConnectObject &simObject)
2274 if (!simObject.isReadyToSend()) {
return false; }
2275 if (simObject.isTerrainProbe()) {
return false; }
2278 const DWORD objectId = simObject.getObjectId();
2281 DataDefinitionRemoteAtc ddAtc;
2282 ddAtc.setDefaultValues();
2283 const QByteArray csBa = simObject.getCallsignByteArray();
2284 const QByteArray airlineBa = simObject.getAircraft().getAirlineIcaoCode().getName().toLatin1();
2285 const QByteArray flightNumberBa = QString::number(simObject.getObjectId()).toLatin1();
2287 ddAtc.copyAtcId(csBa.constData());
2288 ddAtc.copyAtcAirline(airlineBa.constData());
2289 ddAtc.copyFlightNumber(flightNumberBa.constData());
2294 static_cast<SIMCONNECT_OBJECT_ID
>(objectId), SIMCONNECT_DATA_SET_FLAG_DEFAULT,
2295 0,
sizeof(DataDefinitionRemoteAtc), &ddAtc),
2296 traceId, simObject,
"Failed so aircraft ATC data", Q_FUNC_INFO,
"SimConnect_SetDataOnSimObject");
2301 void CSimulatorFsxCommon::sendToggledLightsToSimulator(
const CSimConnectObject &simObj,
2304 if (!simObj.isReadyToSend()) {
return; }
2306 const CAircraftLights lightsIsState = simObj.getCurrentLightsInSimulator();
2307 if (lightsWanted == lightsIsState) {
return; }
2308 if (!force && lightsWanted == simObj.getLightsAsSent()) {
return; }
2309 const CCallsign callsign(simObj.getCallsign());
2315 simObjToUpdate.setLightsAsSent(lightsWanted);
2319 if (!lightsIsState.
isNull())
2321 const DWORD objectId = simObj.getObjectId();
2327 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST,
2328 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
2329 trace, simObj,
"Toggle taxi lights", Q_FUNC_INFO,
"EventToggleTaxiLights");
2334 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST,
2335 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
2336 trace, simObj,
"Toggle nav.lights", Q_FUNC_INFO,
"EventToggleNavLights");
2341 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST,
2342 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
2343 trace, simObj,
"Toggle becon lights", Q_FUNC_INFO,
"EventToggleBeaconLights");
2348 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST,
2349 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
2350 trace, simObj,
"Toggle logo lights", Q_FUNC_INFO,
"EventToggleLogoLights");
2355 SimConnect_TransmitClientEvent(
m_hSimConnect, objectId, EventToggleRecognitionLights, 0.0,
2356 SIMCONNECT_GROUP_PRIORITY_HIGHEST,
2357 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
2358 trace, simObj,
"Toggle recognition lights", Q_FUNC_INFO,
"EventToggleRecognitionLights");
2363 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST,
2364 SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY),
2365 trace, simObj,
"Toggle cabin lights", Q_FUNC_INFO,
"EventToggleCabinLights");
2373 this->
debugLogMessage(Q_FUNC_INFO, QStringLiteral(
"Missing light state in simulator for '%1', model '%2'")
2374 .arg(callsign.
asString(), simObj.getAircraftModelString()));
2377 const QPointer<CSimulatorFsxCommon> myself(
this);
2379 if (!myself) {
return; }
2382 if (!currentSimObject.isReadyToSend()) { return; }
2383 if (lightsWanted != currentSimObject.getLightsAsSent())
2389 this->
debugLogMessage(Q_FUNC_INFO, QStringLiteral(
"Resending light state for '%1', model '%2'")
2390 .arg(callsign.
asString(), simObj.getAircraftModelString()));
2392 this->sendToggledLightsToSimulator(currentSimObject, lightsWanted,
true);
2396 SIMCONNECT_DATA_INITPOSITION
2401 Q_ASSERT_X(!situation.
isPositionNull(), Q_FUNC_INFO,
"Missing position");
2406 if (forceUnderflowDetection)
2409 position.Altitude = alt.
value(CLengthUnit::ft());
2413 position.Pitch = -situation.
getPitch().
value(CAngleUnit::deg());
2414 position.Bank = -situation.
getBank().
value(CAngleUnit::deg());
2416 position.OnGround = 0U;
2419 position.Airspeed =
static_cast<DWORD>(qRound(gsKts));
2426 position.Airspeed = 0U;
2428 else { position.Airspeed =
static_cast<DWORD>(qRound(gsKts)); }
2433 const bool onGround = situation.
isOnGround();
2434 position.OnGround = onGround ? 1U : 0U;
2438 if (forceUnderflowDetection && position.OnGround == 0 &&
2439 !CAircraftSituation::isCorrectedAltitude(altCorrection))
2444 if (position.Airspeed < 2)
2446 position.OnGround = 1U;
2450 .
warning(u
"Force GND flag for underflow protection");
2459 if (CBuildConfig::isLocalDeveloperDebugBuild())
2479 SIMCONNECT_DATA_INITPOSITION position;
2480 position.Latitude = coordinate.
latitude().
value(CAngleUnit::deg());
2481 position.Longitude = coordinate.
longitude().
value(CAngleUnit::deg());
2484 position.Heading = 0;
2485 position.Airspeed = 0;
2488 position.OnGround = 0;
2494 SIMCONNECT_DATA_LATLONALT lla;
2495 lla.Latitude = coordinate.
latitude().
value(CAngleUnit::deg());
2517 bool CSimulatorFsxCommon::requestPositionDataForSimObject(
const CSimConnectObject &simObject,
2518 SIMCONNECT_PERIOD period)
2522 if (simObject.
isPending()) {
return false; }
2527 const SIMCONNECT_DATA_REQUEST_ID reqId =
static_cast<SIMCONNECT_DATA_REQUEST_ID
>(
2528 simObject.
getRequestId(CSimConnectDefinitions::SimObjectPositionData));
2533 simObject,
"Cannot request simulator data", Q_FUNC_INFO,
"SimConnect_RequestDataOnSimObject");
2537 m_requestSimObjectDataCount++;
2544 bool CSimulatorFsxCommon::requestTerrainProbeData(
const CSimConnectObject &simObject,
2547 static const QString w(
"Cannot request terrain probe data for id '%1'");
2548 const SIMCONNECT_DATA_REQUEST_ID requestId =
2549 simObject.getRequestId(CSimConnectDefinitions::SimObjectPositionData);
2550 const DWORD objectId = simObject.getObjectId();
2552 SimConnect_RequestDataOnSimObject(
m_hSimConnect,
static_cast<SIMCONNECT_DATA_REQUEST_ID
>(requestId),
2554 static_cast<SIMCONNECT_OBJECT_ID
>(objectId), SIMCONNECT_PERIOD_ONCE),
2555 simObject, w.arg(requestId), Q_FUNC_INFO,
"SimConnect_RequestDataOnSimObject");
2556 const bool ok = isOk(result);
2561 bool CSimulatorFsxCommon::requestLightsForSimObject(
const CSimConnectObject &simObject)
2567 const SIMCONNECT_DATA_REQUEST_ID requestId = simObject.getRequestId(CSimConnectDefinitions::SimObjectLights);
2570 CSimConnectDefinitions::DataRemoteAircraftLights, simObject.getObjectId(),
2571 SIMCONNECT_PERIOD_SECOND),
2572 simObject,
"Cannot request lights data", Q_FUNC_INFO,
"SimConnect_RequestDataOnSimObject");
2573 return isOk(result);
2576 bool CSimulatorFsxCommon::requestModelInfoForSimObject(
const CSimConnectObject &simObject)
2582 const SIMCONNECT_DATA_REQUEST_ID requestId = simObject.getRequestId(CSimConnectDefinitions::SimObjectModel);
2586 simObject.getObjectId(), SIMCONNECT_PERIOD_ONCE),
2587 simObject,
"Cannot request model info", Q_FUNC_INFO,
"SimConnect_RequestDataOnSimObject");
2588 return isOk(result);
2591 bool CSimulatorFsxCommon::stopRequestingDataForSimObject(
const CSimConnectObject &simObject)
2593 if (!simObject.hasValidRequestAndObjectId()) {
return false; }
2597 SIMCONNECT_DATA_REQUEST_ID requestId = simObject.getRequestId(CSimConnectDefinitions::SimObjectPositionData);
2601 simObject.getObjectId(), SIMCONNECT_PERIOD_NEVER),
2602 simObject,
"Stopping position request", Q_FUNC_INFO,
"SimConnect_RequestDataOnSimObject");
2604 requestId = simObject.getRequestId(CSimConnectDefinitions::SimObjectLights);
2607 CSimConnectDefinitions::DataRemoteAircraftLights, simObject.getObjectId(),
2608 SIMCONNECT_PERIOD_NEVER),
2609 simObject,
"Stopping lights request", Q_FUNC_INFO,
"SimConnect_RequestDataOnSimObject");
2610 return isOk(hr1, hr2);
2615 CSimulatorFsCommon::initSimulatorInternals();
2629 CSimulatorFsCommon::reset();
2632 m_simulatingChangedTs = -1;
2633 m_simConnected =
false;
2634 m_simSimulating =
false;
2635 m_sbDataReceived = 0;
2636 m_requestIdSimObjAircraft =
static_cast<SIMCONNECT_DATA_REQUEST_ID
>(RequestSimObjAircraftStart);
2637 m_dispatchErrors = 0;
2638 m_receiveExceptionCount = 0;
2641 m_sendIdTraces.clear();
2646 const bool reinitProbe =
2648 this->removeAllProbes();
2651 CSimulatorFsCommon::clearAllRemoteAircraftData();
2653 m_addPendingAircraft.clear();
2654 m_simConnectObjectsPositionAndPartsTraces.clear();
2659 QPointer<CSimulatorFsxCommon> myself(
this);
2670 m_sbDataReceived = 0;
2671 CSimulatorFsCommon::onOwnModelChanged(newModel);
2674 QString CSimulatorFsxCommon::fsxPositionToString(
const SIMCONNECT_DATA_INITPOSITION &position)
2676 static const QString positionStr(
2677 "Lat: %1deg lng: %2deg alt: %3ft pitch: %4deg bank: %5deg hdg: %6deg airspeed: %7kts onGround: %8");
2678 return positionStr.arg(position.Latitude)
2679 .arg(position.Longitude)
2680 .arg(position.Altitude)
2681 .arg(position.Pitch)
2683 .arg(position.Heading)
2684 .arg(position.Airspeed)
2685 .arg(position.OnGround);
2688 CCallsignSet CSimulatorFsxCommon::getCallsignsMissingInProvider()
const
2693 return simObjectCallsigns.difference(providerCallsigns);
2696 void CSimulatorFsxCommon::traceSendId(
const CSimConnectObject &simObject,
const QString &functionName,
2697 const QString &details,
bool forceTrace)
2700 if (MaxSendIdTraces < 1) {
return; }
2702 const HRESULT hr = SimConnect_GetLastSentPacketID(
m_hSimConnect, &dwLastId);
2704 if (m_sendIdTraces.size() > MaxSendIdTraces) { m_sendIdTraces.removeLast(); }
2705 const TraceFsxSendId trace(dwLastId, simObject,
2706 details.isEmpty() ? functionName : details % u
", " % functionName);
2707 m_sendIdTraces.push_front(trace);
2711 const QString &functionDetails)
2714 return this->
logAndTraceSendId(hr, empty, warningMsg, functionName, functionDetails);
2718 const QString &warningMsg,
const QString &functionName,
2719 const QString &functionDetails)
2726 const QString &warningMsg,
const QString &functionName,
2727 const QString &functionDetails)
2729 if (traceSendId) { this->traceSendId(simObject, functionName, functionDetails); }
2730 if (isOk(hr)) {
return hr; }
2742 if (trace.sendId == sendId) {
return trace; }
2747 QString CSimulatorFsxCommon::getSendIdTraceDetails(
DWORD sendId)
const
2749 const TraceFsxSendId trace = this->getSendIdTrace(sendId);
2750 if (trace.sendId == sendId) {
return this->getSendIdTraceDetails(trace); }
2754 QString CSimulatorFsxCommon::getSendIdTraceDetails(
const TraceFsxSendId &trace)
const
2756 static const QString d(
"Send id: %1 obj.id.: %2 SimObj: %3 | '%4'");
2757 if (trace.isInvalid()) {
return QString(); }
2761 return d.arg(trace.sendId).arg(simObject.getObjectId()).arg(simObject.toQString(), trace.comment);
2764 int CSimulatorFsxCommon::removeAllProbes()
2770 for (
const CSimConnectObject &probeSimObject : probes)
2772 if (!probeSimObject.isConfirmedAdded()) {
continue; }
2773 const SIMCONNECT_DATA_REQUEST_ID requestId =
2774 probeSimObject.getRequestId(CSimConnectDefinitions::SimObjectRemove);
2775 const HRESULT result = SimConnect_AIRemoveObject(
2776 m_hSimConnect,
static_cast<SIMCONNECT_OBJECT_ID
>(probeSimObject.getObjectId()), requestId);
2777 if (isOk(result)) { c++; }
2780 CLogMessage(
this).
warning(u
"Removing probe '%1' from simulator failed") << probeSimObject.getObjectId();
2788 CSimConnectObject CSimulatorFsxCommon::insertNewSimConnectObject(
const CSimulatedAircraft &aircraft,
2791 const CSimConnectObject &removedPendingObject)
2797 simObject.copyAddingFailureCounters(removedPendingObject);
2798 simObject.resetTimestampToNow();
2802 CSimConnectObject simObject;
2803 if (m_simConnectObjectsPositionAndPartsTraces.contains(aircraft.
getCallsign()))
2806 simObject = m_simConnectObjectsPositionAndPartsTraces[aircraft.
getCallsign()];
2807 m_simConnectObjectsPositionAndPartsTraces.remove(aircraft.
getCallsign());
2808 simObject.resetState();
2809 simObject.setRequestId(requestId);
2810 simObject.setAircraft(aircraft);
2818 simObject.copyAddingFailureCounters(removedPendingObject);
2819 simObject.setType(type);
2824 const CAltitude &CSimulatorFsxCommon::terrainProbeAltitude()
2826 static const CAltitude alt(50000, CLengthUnit::ft());
2832 return QString::fromLatin1(fsxChar, size);
2835 QString CSimulatorFsxCommon::requestIdToString(
DWORD requestId)
2845 static const QString req(
"%1 %2 %3");
2846 return req.arg(requestId)
2857 case CSimConnectObject::TerrainProbe:
2858 start = RequestSimObjTerrainProbeStart;
2859 end = RequestSimObjTerrainProbeEnd;
2861 case CSimConnectObject::AircraftNonAtc:
2862 case CSimConnectObject::AircraftSimulatedObject:
2864 start = RequestSimObjAircraftStart;
2865 end = RequestSimObjAircraftEnd;
2869 const int id = CMathUtils::randomInteger(start,
end);
2870 return static_cast<DWORD>(id);
2873 CCallsignSet CSimulatorFsxCommon::physicallyRemoveAircraftNotInProvider()
2875 const CCallsignSet callsignsToBeRemoved(this->getCallsignsMissingInProvider());
2876 if (callsignsToBeRemoved.isEmpty()) {
return callsignsToBeRemoved; }
2882 QStringLiteral(
"CS: '%1'").arg(callsignsToBeRemoved.toStringList().join(
", ")));
2884 return callsignsToBeRemoved;
2887 void CSimulatorFsxCommon::physicallyRemoveAircraftNotInProviderAsync()
2889 const QPointer<CSimulatorFsxCommon> myself(
this);
2892 CSimulatorFsxCommon::physicallyRemoveAircraftNotInProvider();
2899 m_timer.setInterval(MinQueryIntervalMs);
2900 m_timer.setObjectName(this->objectName().append(
":m_timer"));
2901 connect(&m_timer, &QTimer::timeout,
this, &CSimulatorFsxCommonListener::checkConnection);
2906 m_simulatorVersion.clear();
2907 m_simConnectVersion.clear();
2908 m_simulatorName.clear();
2909 m_simulatorDetails.clear();
2917 this->disconnectFromSimulator();
2922 if (!m_timer.isActive()) {
return; }
2925 QPointer<CSimulatorFsxCommonListener> myself(
this);
2928 this->checkConnection();
2937 if (m_simulatorName.isEmpty()) {
return ISimulatorListener::backendInfo(); }
2938 return m_simulatorDetails;
2941 void CSimulatorFsxCommonListener::checkConnection()
2943 Q_ASSERT_X(!CThreadUtils::thisIsMainThread(), Q_FUNC_INFO,
"Expect to run in background");
2946 if (this->
isShuttingDown() || this->thread()->isInterruptionRequested())
2958 if (!this->connectToSimulator()) {
break; }
2962 const HRESULT result =
2963 SimConnect_CallDispatch(m_hSimConnect, CSimulatorFsxCommonListener::SimConnectProc,
this);
2966 if (this->
isShuttingDown() || this->thread()->isInterruptionRequested())
2973 check = this->checkVersionAndSimulator();
2977 this->adjustTimerInterval(t.elapsed());
2981 void CSimulatorFsxCommonListener::adjustTimerInterval(qint64 checkTimeMs)
2984 CLogMessage(
this).
debug(u
"Checked sim.'%1' connection in %2ms") << sim << checkTimeMs;
2985 if (checkTimeMs > qRound(1.25 * MinQueryIntervalMs))
2987 const int newIntervalMs = qRound(1.2 * checkTimeMs / 1000.0) * 1000;
2988 CLogMessage(
this).
debug(u
"Check for simulator sim.'%1' connection in %2ms, too slow. Setting %3ms")
2989 << sim << checkTimeMs << newIntervalMs;
2990 if (m_timer.interval() != newIntervalMs) { m_timer.setInterval(newIntervalMs); }
2994 if (m_timer.interval() != MinQueryIntervalMs) { m_timer.setInterval(MinQueryIntervalMs); }
3001 bool CSimulatorFsxCommonListener::checkVersionAndSimulator()
const
3004 const QString connectedSimName = m_simulatorName.toLower().trimmed();
3006 if (connectedSimName.isEmpty()) {
return false; }
3007 if (pluginSim.isP3D())
3010 return connectedSimName.contains(
"lockheed") || connectedSimName.contains(
"martin") ||
3011 connectedSimName.contains(
"p3d") || connectedSimName.contains(
"prepar");
3013 else if (pluginSim.isFSX())
3016 return connectedSimName.contains(
"fsx") || connectedSimName.contains(
"microsoft") ||
3017 connectedSimName.contains(
"simulator x");
3019 else if (pluginSim.isMSFS())
3022 return connectedSimName.contains(
"kittyhawk");
3024 else if (pluginSim.isMSFS2024())
3027 return connectedSimName.contains(
"sunrise");
3032 bool CSimulatorFsxCommonListener::checkSimConnectDll()
const
3035 if (!simConnectInfo.
errorMsg.isEmpty()) {
return false; }
3039 bool CSimulatorFsxCommonListener::connectToSimulator()
3041 if (m_simConnected) {
return true; }
3042 const HRESULT result = SimConnect_Open(&m_hSimConnect,
sApp->
swiftVersionChar(),
nullptr, 0,
nullptr, 0);
3043 const bool ok = isOk(result);
3044 m_simConnected = ok;
3048 bool CSimulatorFsxCommonListener::disconnectFromSimulator()
3050 if (!m_simConnected) {
return false; }
3051 SimConnect_Close(m_hSimConnect);
3052 m_hSimConnect =
nullptr;
3053 m_simConnected =
false;
3057 void CSimulatorFsxCommonListener::SimConnectProc(SIMCONNECT_RECV *pData,
DWORD cbData,
void *pContext)
3061 switch (pData->dwID)
3063 case SIMCONNECT_RECV_ID_OPEN:
3065 SIMCONNECT_RECV_OPEN *
event =
static_cast<SIMCONNECT_RECV_OPEN *
>(pData);
3066 simListener->m_simulatorVersion = QStringLiteral(
"%1.%2.%3.%4")
3067 .arg(event->dwApplicationVersionMajor)
3068 .arg(event->dwApplicationVersionMinor)
3069 .arg(event->dwApplicationBuildMajor)
3070 .arg(event->dwApplicationBuildMinor);
3071 simListener->m_simConnectVersion = QStringLiteral(
"%1.%2.%3.%4")
3072 .arg(event->dwSimConnectVersionMajor)
3073 .arg(event->dwSimConnectVersionMinor)
3074 .arg(event->dwSimConnectBuildMajor)
3075 .arg(event->dwSimConnectBuildMinor);
3077 simListener->m_simulatorDetails = QStringLiteral(
"Name: '%1' Version: %2 SimConnect: %3")
3078 .arg(simListener->m_simulatorName, simListener->m_simulatorVersion,
3079 simListener->m_simConnectVersion);
3081 << simListener->getPluginInfo().getIdentifier() << simListener->backendInfo();
3084 if (msg.
getMessage() != simListener->m_lastMessage.getMessage())
3086 CLogMessage::preformatted(msg);
3087 simListener->m_lastMessage = msg;
3091 case SIMCONNECT_RECV_ID_EXCEPTION:
break;
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
const char * swiftVersionChar()
swift info string
bool isShuttingDown() const
Is application shutting down?
virtual void callbackReceivedRequestedElevation(const swift::misc::geo::CElevationPlane &plane, const swift::misc::aviation::CCallsign &callsign, bool isWater)
A requested elevation has been received.
bool showDebugLogMessage() const
Show log messages?
bool addLoopbackSituation(const swift::misc::aviation::CAircraftSituation &situation)
Add a loopback situation if logging is enabled.
bool isEqualLastSent(const swift::misc::aviation::CAircraftSituation &compare) const
Equal to last sent situation.
bool updateOwnSituationAndGroundElevation(const swift::misc::aviation::CAircraftSituation &situation)
Update own aircraft position and if suitable use it to update ground elevation.
bool isUpdateAllRemoteAircraft(qint64 currentTimestamp=-1) const
Do update all remote aircraft?
virtual bool isShuttingDown() const
Is overall (swift) application shutting down.
int m_timerId
dispatch timer id
void requestedElevation(const swift::misc::aviation::CCallsign &callsign)
Requested elevation, call pending.
bool m_updateRemoteAircraftInProgress
currently updating remote aircraft
virtual bool isShuttingDownDisconnectedOrNoAircraft() const
Shutting down, disconnected, or no remote aircraft.
void physicallyAddingRemoteModelFailed(const swift::misc::simulation::CSimulatedAircraft &remoteAircraft, bool disabled, bool requestFailover, const swift::misc::CStatusMessage &message)
Adding the remote model failed.
void rememberElevationAndSimulatorCG(const swift::misc::aviation::CCallsign &callsign, const swift::misc::simulation::CAircraftModel &model, bool likelyOnGroundElevation, const swift::misc::geo::CElevationPlane &elevation, const swift::misc::physical_quantities::CLength &simulatorCG)
Set elevation and CG in the providers and for auto publishing.
bool isAircraftInRangeOrTestMode(const swift::misc::aviation::CCallsign &callsign) const
Test version aware version of isAircraftInRange.
void finishUpdateRemoteAircraftAndSetStatistics(qint64 startTime, bool limited=false)
Update stats and flags.
bool isTestMode() const
Test mode? (driver can skip code parts etc., driver dependent)
void debugLogMessage(const QString &msg)
Display a debug log message based on swift::misc::simulation::CInterpolationAndRenderingSetup remark ...
void emitSimulatorCombinedStatus(SimulatorStatus oldStatus=Unspecified)
Emit the combined status.
int m_statsUpdateAircraftRuns
statistics update count
swift::misc::simulation::CSimulatedAircraftList m_addAgainAircraftWhenRemoved
add this model again when removed, normally used to change model
swift::misc::simulation::CSimulatorInternals m_simulatorInternals
setup read from the sim
void logAddingAircraftModel(const swift::misc::simulation::CSimulatedAircraft &aircraft) const
Unified qeeing aircraft message.
@ Disconnected
not connected, and hence not simulating/paused
@ Simulating
Is the simulator actually simulating?
swift::misc::simulation::CInterpolationAndRenderingSetupPerCallsign getInterpolationSetupConsolidated(const swift::misc::aviation::CCallsign &callsign, bool forceFullUpdate) const
Consolidate setup with other data like from swift::misc::simulation::IRemoteAircraftProvider.
virtual SimulatorStatus getSimulatorStatus() const
Combined status.
swift::misc::simulation::settings::CSpecializedSimulatorSettings getSimulatorSettings() const
Settings for current simulator.
swift::misc::simulation::CInterpolationLogger m_interpolationLogger
log.interpolation
bool isUpdateAircraftLimitedWithStats(qint64 startTime=-1)
Limited as ISimulator::isUpdateAircraftLimited plus updating statistics.
void safeKillTimer()
Kill timer if id is valid.
void aircraftRenderingChanged(const swift::misc::simulation::CSimulatedAircraft &aircraft)
Aircraft rendering changed.
bool isFlightNetworkConnected() const
Is the flight network connected.
virtual bool isShuttingDownOrDisconnected() const
Shutting down or disconnected?
void driverMessages(const swift::misc::CStatusMessageList &messages)
Relevant simulator messages to be explicitly displayed.
swift::misc::aviation::CAircraftSituationPerCallsign m_lastSentSituations
last situations sent to simulator
void rememberLastSent(const swift::misc::aviation::CAircraftSituation &sent)
Remember as last sent.
Interface to a simulator listener.
const swift::misc::simulation::CSimulatorPluginInfo & getPluginInfo() const
Corresponding info.
void simulatorStarted(const swift::misc::simulation::CSimulatorPluginInfo &info)
Emitted when the listener discovers the simulator running.
virtual bool isShuttingDown() const
Overall (swift) application shutting down.
void check()
Check simulator availability.
iterator push_back(const T &value)
Synonym for insert.
const CIdentifier & identifier() const
Get identifier.
Value object encapsulating information identifying a component of a modular distributed swift process...
Class for emitting a log message.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
bool isEmpty() const
Message empty.
Derived & log(StatusSeverity s, const char16_t(&m)[N])
Set the severity and format string.
Derived & error(const char16_t(&format)[N])
Set the severity to error, providing a format string.
Derived & debug()
Set the severity to debug.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
bool contains(const T &object) const
Return true if there is an element equal to given object. Uses the most efficient implementation avai...
void push_back(const T &value)
Appends an element at the end of the sequence.
void clear()
Removes all elements in the sequence.
bool isEmpty() const
Synonym for empty.
Utility methods for simple line parsing used with the command line.
bool toBool(int index, bool def=false) const
Part as bool.
bool matchesPart(int index, const QString &toMatch, Qt::CaseSensitivity cs=Qt::CaseInsensitive) const
Matches given part.
bool hasPart(int index) const
Existing part.
Streamable status message, e.g.
bool isWarningOrAbove() const
Warning or above.
StatusSeverity getSeverity() const
Message severity.
QString getMessage() const
Message.
Status messages, e.g. from Core -> GUI.
CStatusMessage toSingleMessage() const
Merge into a single message.
void setMSecsSinceEpoch(qint64 mSecsSinceEpoch)
Timestamp as ms value.
Value object encapsulating information about aircraft's engines.
Value object encapsulating a list of aircraft engines.
Value object encapsulating information about aircraft's lights.
bool isRecognitionOn() const
Recognition lights on?
bool isCabinOn() const
Cabin lights on?
bool isLandingOn() const
Landing lights on?
bool isBeaconOn() const
Beacon lights on?
bool isNavOn() const
Nac lights on?
bool isLogoOn() const
Logo lights on?
bool isTaxiOn() const
Taxi lights on?
bool isStrobeOn() const
Strobes lights on?
Value object encapsulating information of aircraft's parts.
bool isNull() const
NULL parts object?
CAircraftLights getAdjustedLights() const
Lights adjusted depending on engines.
PartsDetails getPartsDetails() const
Get parts details.
int getFlapsPercent() const
Get flaps position in percent.
Value object encapsulating information of an aircraft's situation.
void setPressureAltitude(const CAltitude &altitude)
Set pressure altitude.
void setGroundSpeed(const physical_quantities::CSpeed &groundspeed)
Set ground speed.
bool setGroundElevation(const aviation::CAltitude &altitude, GndElevationInfo info, bool transferred=false)
Elevation of the ground directly beneath at the given situation.
const CHeading & getHeading() const
Get heading.
void setBank(const physical_quantities::CAngle &bank)
Set bank (angle)
void setHeading(const CHeading &heading)
Set heading.
const CAltitude & geodeticHeight() const
Height, ellipsoidal or geodetic height (used in GPS)
AltitudeCorrection
How was altitude corrected?
bool isOnGroundInfoAvailable() const
On ground info available?
void setAltitude(const CAltitude &altitude)
Set altitude.
bool isPositionNull() const
Position null?
bool isOnGround() const
Is on ground?
CAltitude getCorrectedAltitude(bool enableDragToGround=true, AltitudeCorrection *correction=nullptr) const
Get altitude under consideration of ground elevation and ground flag.
const physical_quantities::CSpeed & getGroundSpeed() const
Get ground speed.
void setOnGroundInfo(const aviation::COnGroundInfo &info)
Set the on ground info.
const CAltitude & getAltitude() const
Get altitude.
void setPitch(const physical_quantities::CAngle &pitch)
Set pitch.
const physical_quantities::CAngle & getBank() const
Get bank (angle)
virtual bool isNull() const
Null situation.
const physical_quantities::CAngle & getPitch() const
Get pitch.
void setVelocity(const CAircraftVelocity &velocity)
Set 6DOF velocity.
bool isMoving() const
Is moving? Means ground speed > epsilon.
void setPosition(const geo::CCoordinateGeodetic &position)
Set position.
List of aircraft situations.
Velocity and angular velocity for 6DOF bodies.
Value object for ICAO classification.
Altitude as used in aviation, can be AGL or MSL altitude.
ReferenceDatum getReferenceDatum() const
Get reference datum (MSL or AGL)
Value object encapsulating information of a callsign.
const QString & asString() const
Get callsign (normalized)
bool isEmpty() const
Is empty?
Value object for a set of callsigns.
QStringList getCallsignStrings(bool sorted=false) const
The callsign strings.
QString getCallsignsAsString(bool sorted=false, const QString &separator=", ") const
Callsigns as string.
void setFrequencyActive(const physical_quantities::CFrequency &frequency)
Set active frequency.
Heading as used in aviation, can be true or magnetic heading.
Value object encapsulating information about an airpot.
swift::misc::physical_quantities::CFrequency getFrequencyStandby() const
Standby frequency.
swift::misc::physical_quantities::CFrequency getFrequencyActive() const
Active frequency.
bool isIdentifying() const
Standby?
bool isInStandby() const
Standby?
bool setTransponderMode(TransponderMode mode)
Set transponder mode.
TransponderMode
Transponder codes.
TransponderMode getTransponderMode() const
Transponder mode.
int removeByCallsigns(const CCallsignSet &callsigns)
Remove all objects with callsigns.
OBJ findFirstByCallsign(const CCallsign &callsign, const OBJ &ifNotFound={}) const
Find the first aircraft by callsign, if none return given one.
int removeByCallsign(const CCallsign &callsign)
Remove all objects with callsign.
swift::misc::aviation::CCallsignSet getCallsigns() const
All callsigns.
bool containsCallsign(const CCallsign &callsign) const
Contains callsign?
QStringList getCallsignStrings(bool sorted=false) const
Get callsign string list.
void setLatitude(const CLatitude &latitude)
Set latitude.
virtual const aviation::CAltitude & geodeticHeight() const
Height, ellipsoidal or geodetic height (used in GPS)
void setGeodeticHeight(const aviation::CAltitude &height)
Set height (ellipsoidal or geodetic height)
void setLongitude(const CLongitude &longitude)
Set longitude.
Plane of same elevation, can be a single point or larger area (e.g. airport)
Geodetic coordinate, a position in 3D space relative to the reference geoid.
virtual CLongitude longitude() const =0
Longitude.
virtual bool isNull() const
Is null, means vector x, y, z == 0.
virtual const aviation::CAltitude & geodeticHeight() const =0
Height, ellipsoidal or geodetic height (used in GPS)
bool isGeodeticHeightNull() const
Geodetic height null?
virtual CLatitude latitude() const =0
Latitude.
QString toQString(bool i18n=false) const
Cast as QString.
Value object encapsulating information of a text message.
bool isPrivateMessage() const
Is private message?
QString asString(bool withSender, bool withRecipient, const QString &separator=", ") const
Whole message as formatted string. Used to display message in a console window.
bool isRadioMessage() const
Is radio message?
bool isSupervisorMessage() const
Supervisor message?
Value object encapsulating information of a user.
Direct in memory access to client (network client) data.
Physical unit angle (radians, degrees)
Physical unit length (length)
bool isNull() const
Is quantity null?
double value(MU unit) const
Value in given unit.
PQ abs() const
Absolute value (always >=0)
Aircraft model (used by another pilot, my models on disk)
const aviation::CCallsign & getCallsign() const
Corresponding callsign if applicable.
bool hasExistingCorrespondingFile() const
Does the corresponding file exist?
const QString & getModelString() const
Model key, either queried or loaded from simulator model.
CStatusMessageList verifyModelData() const
Verify the model data.
const QString & getFileName() const
File name (corresponding data for simulator, only available if representing simulator model.
bool isSendingGndFlagToSimulator() const
Send GND flag to simulator.
InterpolatorMode getInterpolatorMode() const
Interpolator mode.
bool isForcingFullInterpolation() const
Full interpolation (skip optimizations like checking if aircraft moves etc.)
Value object for interpolator and rendering per callsign.
const CInterpolationStatus & getInterpolationStatus() const
Get status.
const aviation::CAircraftSituation & getInterpolatedSituation() const
Get situation.
const CPartsStatus & getPartsStatus() const
Get status.
bool hasValidSituation() const
Is the corresponding position valid?
bool isInterpolated() const
Did interpolation succeed?
bool updateOwnParts(const aviation::CAircraftParts &parts)
Update own parts.
bool updateOwnCG(const physical_quantities::CLength &cg)
Update own aircraft's CG (aka vertical offset)
bool updateCockpit(const swift::misc::simulation::CSimulatedAircraft &aircraft, const swift::misc::CIdentifier &originator)
swift::misc::geo::CCoordinateGeodetic getOwnAircraftPosition() const
Own aircraft's position.
CSimulatedAircraft getOwnAircraft() const
Own aircraft.
bool isReusedParts() const
Is a reused parts object?
bool isSupportingParts() const
Supporting parts.
aviation::CCallsignSet getAircraftInRangeCallsigns() const
Unique callsigns for aircraft in range.
bool isAircraftInRange(const aviation::CCallsign &callsign) const
Is aircraft in range?
bool updateMultipleAircraftEnabled(const aviation::CCallsignSet &callsigns, bool enabledForRendering)
Enable/disable aircraft.
aviation::CAircraftSituationList remoteAircraftSituations(const aviation::CCallsign &callsign) const
Rendered aircraft situations (per callsign, time history)
int getAircraftInRangeCount() const
Count remote aircraft.
bool updateAircraftEnabled(const aviation::CCallsign &callsign, bool enabledForRendering)
Enable/disable aircraft and follow up logic like sending signals.
IRemoteAircraftProvider * getRemoteAircraftProvider() const
Get the aircraft provider.
bool updateCGAndModelString(const aviation::CCallsign &callsign, const physical_quantities::CLength &cg, const QString &modelString)
Update the CG and model string.
bool updateAircraftRendered(const aviation::CCallsign &callsign, bool rendered)
Set aircraft rendered.
Comprehensive information of an aircraft.
bool hasModelString() const
Has model string?
const aviation::CAircraftSituation & getSituation() const
Get situation.
const aviation::CComSystem & getCom2System() const
Get COM2 system.
const aviation::CTransponder & getTransponder() const
Get transponder.
bool setRendered(bool rendered)
Rendered?
const aviation::CCallsign & getCallsign() const
Get callsign.
bool isTerrainProbe() const
Terrain probe?
QString getCallsignAsString() const
Get callsign.
const aviation::CComSystem & getCom1System() const
Get COM1 system.
const QString & getModelString() const
Get model string.
Value object encapsulating a list of aircraft.
bool replaceOrAddByCallsign(const CSimulatedAircraft &aircraft)
Replace or add by callsign.
Simple hardcoded info about the corresponding simulator.
void setValue(const QString &name, const QString &value)
Set value.
Describing a simulator plugin.
const QString & getIdentifier() const
Identifier.
const CSimulatorInfo & getSimulatorInfo() const
Simulator info object.
bool isLogCallsign(const aviation::CCallsign &callsign) const
Is callsign marked for logging.
CInterpolationAndRenderingSetupPerCallsign getInterpolationSetupPerCallsignOrDefault(const aviation::CCallsign &callsign) const
Get the setup for callsign, if not existing the global setup.
Direct threadsafe in memory access to own aircraft.
Direct thread safe in memory access to remote aircraft.
CSimulatorPluginInfo getSimulatorPluginInfo() const
Get the represented plugin.
CSimulatorInfo getSimulatorInfo() const
Get the represented simulator.
QString getSimulatorDetails() const
Simulator details as set from the running simulator.
Utility, providing FS aircraft.cfg entries.
QString getTitlesAsString(bool sorted, const QString &separator=", ") const
All titles as string.
bool containsTitle(const QString &title) const
Can check if a title (model string) is known.
bool isAddingAsSimulatedObjectEnabled() const
Use simulated object adding.
void setSbOffsetsEnabled(bool enable)
Use SB offsets?
void setAddingAsSimulatedObjectEnabled(bool enable)
Use simulated object adding.
bool isSbOffsetsEnabled() const
Are SB offsets enabled.
CFsxP3DSettings getSettings(const CSimulatorInfo &sim) const
Settings per simulator.
CStatusMessage setSettings(const CFsxP3DSettings &settings, const CSimulatorInfo &simulator)
Set settings per simulator.
Allows to have specific utility functions for each simulator.
QStringList getModelDirectoriesOrDefault() const
Model directories or default.
Common base class for MS flight simulators.
swift::misc::aviation::CComSystem m_simCom1
cockpit COM1 state in simulator
swift::misc::aviation::CSelcal m_selcal
SELCAL as in cockpit.
swift::misc::aviation::CComSystem m_simCom2
cockpit COM2 state in simulator
int m_ownAircraftUpdateCycles
own aircraft updates, even with 50 updates/sec long enough even for 32bit
swift::misc::aviation::CTransponder m_simTransponder
cockpit xpdr state in simulator
int m_skipCockpitUpdateCycles
skip some update cycles to allow changes in simulator cockpit to be set
SimObjectRequest
SimObject requests used for AI aircraft and probes.
@ SimObjectEndMarker
end marker, do NOT remove, also means invalid
Request
SimConnect request IDs.
@ RequestEndMarker
free request ids can start here
@ RequestMSFSTransponder
MSFS XPDR mode/ident.
@ RequestSbData
SB client area / XPDR mode.
static const QString & requestToString(Request request)
Request to string.
static HRESULT initDataDefinitionsWhenConnected(const HANDLE hSimConnect, const swift::misc::simulation::CSimulatorInfo &simInfo)
Initialize all data definitions.
static const QString & simObjectRequestToString(SimObjectRequest simObjectRequest)
Request to string.
@ DataRemoteAircraftSetData
set model data such as airline
@ DataClientAreaSbConnected
SB connected with network 0x7b81/1.
@ DataRemoteAircraftSetPosition
the position which will be set
@ DataClientAreaSb
whole SB area, see http://squawkbox.ca/doc/sdk/fsuipc.php
@ DataRemoteAircraftModelData
model data eventually used and reported back from simulator
@ DataClientAreaSbIdent
SB ident single value 0x7b93/19.
@ DataRemoteAircraftGetPosition
get position to evaluate altitude / AGL
@ DataClientAreaSbStandby
SB standby 0x7b91/17.
Class representing a SimConnect object.
bool isPendingAdded() const
Object is requested in simulator, not yet confirmed added.
bool isConfirmedAdded() const
Adding is confirmed.
DWORD getObjectId() const
Get SimConnect object id.
QString toQString() const
SimObject as string.
bool hasValidRequestAndObjectId() const
Was the object really added to simulator.
bool hasCurrentLightsInSimulator() const
Received lights in simulator.
bool isPending() const
Pending added or removed?
bool isRemovedWhileAdding() const
Special states.
const swift::misc::simulation::CSimulatedAircraft & getAircraft() const
Simulated aircraft (as added)
static SimObjectType requestIdToType(DWORD requestId)
Type of id.
static const QString & typeToString(SimObjectType type)
Type to string.
DWORD getRequestId() const
Get SimConnect request id.
const swift::misc::aviation::CCallsign & getCallsign() const
Get callsign.
SIMCONNECT_PERIOD getSimDataPeriod() const
How often do we request data from simulator for this remote aircraft.
void setRemovedWhileAdding(bool removedWhileAdding)
Special states.
bool isTerrainProbe() const
Probe?
bool isPendingRemoved() const
Removing is pending.
void setPendingRemoved(bool pending)
Marked as pending for removal.
bool removeByOtherSimObject(const CSimConnectObject &otherSimObj)
Remove by object id or request id.
int countPendingAdded() const
Number of pending added.
swift::misc::aviation::CCallsignSet getAllCallsigns(bool withoutProbes=true) const
Get all callsigns.
CSimConnectObject getSimObjectForObjectId(DWORD objectId) const
Get object per object id.
bool insert(const CSimConnectObject &simObject, bool updateTimestamp=false)
Insert.
CSimConnectObject getSimObjectForOtherSimObject(const CSimConnectObject &otherSimObj) const
Get by request or object id, just as possible.
bool setSimConnectObjectIdForRequestId(DWORD requestId, DWORD objectId)
Set ID of a SimConnect object, so far we only have an request id in the object.
CSimConnectObject getOldestNotPendingProbe() const
Get a non pending probe.
swift::misc::aviation::CCallsignSet getPendingAddedCallsigns() const
Callsigns of pending added callsigns.
CSimConnectObject getOldestObject() const
Get the oldest object.
QString getAllCallsignStringsAsString(bool sorted=false, const QString &separator=", ") const
Get all callsign strings as string.
bool containsPendingAdded() const
Pending add condition.
int removeAllProbes()
Remove all the probes.
int removeCallsigns(const swift::misc::aviation::CCallsignSet &callsigns)
Remove callsigns.
QList< CSimConnectObject > getProbes() const
All probes.
CSimConnectObjects removeOutdatedPendingAdded(CSimConnectObject::SimObjectType type)
Remove all pending added objects.
QStringList getAllCallsignStrings(bool sorted=false, bool withoutProbes=true) const
Get all callsign strings.
FSX Simulator Implementation.
bool isUsingFsxTerrainProbe() const
FSX Terrain probe.
virtual bool updateOwnSimulatorSelcal(const swift::misc::aviation::CSelcal &selcal, const swift::misc::CIdentifier &originator)
Update own aircraft cockpit (usually from context)
virtual bool isPhysicallyRenderedAircraft(const swift::misc::aviation::CCallsign &callsign) const
Is the aircraft rendered (displayed in simulator)? This shall only return true if the aircraft is rea...
virtual void setTrueAltitude(swift::misc::aviation::CAircraftSituation &aircraftSituation, const swift::simplugin::fsxcommon::DataDefinitionOwnAircraft &simulatorOwnAircraft)
Customization point for adjusting altitude to compensate for temperature effect.
virtual void displayTextMessage(const swift::misc::network::CTextMessage &message) const
Display a text message.
virtual swift::misc::CStatusMessageList debugVerifyStateAfterAllAircraftRemoved() const
Debug function to check state after all aircraft have been removed.
SIMCONNECT_DATA_REQUEST_ID obtainRequestIdForSimObjTerrainProbe()
Get new request id, overflow safe.
static bool isValid180Deg(double deg)
Valid 180degrees value.
bool removeSimObjectForTrace(const TraceFsxSendId &trace)
Remove the CSimConnectObject linked in the trace.
virtual void setFlightNetworkConnected(bool connected)
Flight network has been connected.
int m_addedProbes
added probes
CSimConnectObjects m_simConnectObjects
AI objects and their object and request ids.
swift::misc::physical_quantities::CLength m_altitudeDelta
FS2020 effect of temperature on altitude.
QMap< DWORD, swift::misc::aviation::CCallsign > m_pendingProbeRequests
pending elevation requests: requestId/aircraft callsign
static QString fsxCharToQString(const char *fsxChar, int size=-1)
Encapsulates creating QString from FSX string data.
static SIMCONNECT_DATA_INITPOSITION coordinateToFsxPosition(const swift::misc::geo::ICoordinateGeodetic &coordinate)
Format conversion.
virtual bool requestElevation(const swift::misc::geo::ICoordinateGeodetic &reference, const swift::misc::aviation::CCallsign &aircraftCallsign)
Request elevation, there is no guarantee the requested elevation will be available in the provider.
static bool isRequestForSimObjTerrainProbe(DWORD requestId)
Request for probe (elevation)?
virtual void displayStatusMessage(const swift::misc::CStatusMessage &message) const
Display a status message in the simulator.
void setTractingSendId(bool trace)
Set tracing on/off.
HRESULT logAndTraceSendId(HRESULT hr, const QString &warningMsg, const QString &functionName, const QString &functionDetails={})
Trace if required, log errors.
virtual void removeCamera(CSimConnectObject &simObject)
Remove camera if any.
virtual int physicallyRemoveAllRemoteAircraft()
Remove all remote aircraft and their data via ISimulator::clearAllRemoteAircraftData.
HANDLE m_hSimConnect
handle to SimConnect object
void setUsingSbOffsetValues(bool use)
Use SB offset values.
virtual bool physicallyAddRemoteAircraft(const swift::misc::simulation::CSimulatedAircraft &newRemoteAircraft)
Add new remote aircraft physically to the simulator.
SIMCONNECT_DATA_REQUEST_ID obtainRequestIdForSimObjAircraft()
Get new request id, overflow safe.
DispatchProc m_dispatchProc
called function for dispatch, can be overriden by specialized P3D function
virtual ~CSimulatorFsxCommon()
Destructor.
virtual void removeObserver(CSimConnectObject &simObject)
Remove observer if any.
virtual void initSimulatorInternals()
Init the internal objects.
virtual bool testSendSituationAndParts(const swift::misc::aviation::CCallsign &callsign, const swift::misc::aviation::CAircraftSituation &situation, const swift::misc::aviation::CAircraftParts &parts)
Send situation/parts for testing.
virtual bool releaseAIControl(const CSimConnectObject &simObject, SIMCONNECT_DATA_REQUEST_ID requestId)
Release AI control.
virtual HRESULT initEventsP3D()
Specific P3D events.
virtual bool disconnectFrom()
Disconnect from simulator.
swift::misc::aviation::CCallsign getCallsignForPendingProbeRequests(DWORD requestId, bool remove)
Callsign for pending request.
bool isAddingAsSimulatedObjectEnabled() const
Allow adding as simulated object instead of non ATC.
void setAddingAsSimulatedObjectEnabled(bool enabled)
Allow adding as simulated object instead of non ATC.
virtual void onOwnModelChanged(const swift::misc::simulation::CAircraftModel &newModel)
Own model has been changed.
virtual swift::misc::aviation::CCallsignSet physicallyRenderedAircraft() const
Physically rendered (displayed in simulator) This shall only return aircraft handled in the simulator...
virtual bool isConnected() const
Are we connected to the simulator?
virtual void resetAircraftStatistics()
Reset the statistics.
virtual bool isSimulating() const
Simulator running?
static SIMCONNECT_DATA_INITPOSITION aircraftSituationToFsxPosition(const swift::misc::aviation::CAircraftSituation &situation, bool sendGnd=true, bool forceUnderflowDetection=false, swift::misc::CStatusMessage *details=nullptr)
Format conversion.
bool m_initFsxTerrainProbes
initialized terrain probes
static CSimConnectDefinitions::SimObjectRequest requestToSimObjectRequest(DWORD requestId)
Sub request type.
virtual QString getStatisticsSimulatorSpecific() const
Allows to print out simulator specific statistics.
static SIMCONNECT_DATA_LATLONALT coordinateToFsxLatLonAlt(const swift::misc::geo::ICoordinateGeodetic &coordinate)
Format conversion.
virtual bool updateOwnSimulatorCockpit(const swift::misc::simulation::CSimulatedAircraft &ownAircraft, const swift::misc::CIdentifier &originator)
Update own aircraft cockpit (usually from context)
bool triggerAutoTraceSendId(qint64 traceTimeMs=AutoTraceOffsetMs)
Trigger tracing ids for some while.
static void registerHelp()
Register help.
static bool isRequestForSimObjAircraft(DWORD requestId)
Request for sim data (request in range of sim data)?
bool m_useFsxTerrainProbe
Use FSX Terrain probe?
bool isTracingSendId() const
Tracing right now?
virtual void timerEvent(QTimerEvent *event)
Timer event (our SimConnect event loop), runs dispatch.
static QByteArray toFsxChar(const QString &string)
Convert to FSX char array.
virtual bool connectTo()
Connect to simulator.
virtual void reset()
Full reset of state.
bool isValidSimObjectNotPendingRemoved(const CSimConnectObject &simObject) const
Valid CSimConnectObject which is NOT pendig removed.
static bool isValidFsxPosition(const SIMCONNECT_DATA_INITPOSITION &fsxPos)
Valid FSX/P3D position.
virtual void clearAllRemoteAircraftData()
Clear all aircraft related data, but do not physically remove the aircraft.
virtual swift::misc::CStatusMessageList getInterpolationMessages(const swift::misc::aviation::CCallsign &callsign) const
Interpolation messages for callsign.
CSimConnectObject getSimObjectForTrace(const TraceFsxSendId &trace) const
CSimConnectObject for trace.
static SIMCONNECT_DATA_PBH aircraftSituationToFsxPBH(const swift::misc::aviation::CAircraftSituation &situation)
Format conversion.
virtual bool physicallyRemoveRemoteAircraft(const swift::misc::aviation::CCallsign &callsign)
Remove remote aircraft from simulator.
virtual void startImpl()
Plugin specific implementation to start listener.
CSimulatorFsxCommonListener(const swift::misc::simulation::CSimulatorPluginInfo &info)
Constructor.
virtual void stopImpl()
Plugin specific implementation to stop listener.
virtual void checkImpl()
Plugin specific implementation to check.
virtual QString backendInfo() const
Info about the backend system (if available)
virtual bool parseDetails(const swift::misc::CSimpleCommandParser &parser)
Backend services of the swift project, like dealing with the network or the simulators.
Free functions in swift::misc.
SWIFT_MISC_EXPORT const QString & boolToOnOff(bool v)
Bool to on/off.
T::const_iterator end(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
SWIFT_MISC_EXPORT const QString & boolToEnabledDisabled(bool v)
Bool to enabled/disabled.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
const std::string & boolToYesNo(bool t)
Yes/no from bool.
unsigned long DWORD
Fake Windows DWORD.
HRESULT s_ok()
Correctly casted values/checks.
bool isFailure(HRESULT result)
Correctly casted values/checks.
bool dtb(double doubleBool)
Correctly casted values/checks.
EventIds
SimConnect Event IDs.
adding struct SIMCONNECT_DATA_PBH not existing in SimConnect FSX
QString errorMsg
error message if any
Data structure for MSFS transponder mode information.
double transponderMode
transponder state simvar
Data struct of our own aircraft.
double rotationVelocityBodyX
Rotation Velocity Body X.
double lightBeacon
Is beacon light on?
double lightNav
Is nav light on?
double velocity
Ground velocity.
double lightLogo
Is logo light on?
double velocityWorldY
Velocity World Y.
double com2ActiveMHz
COM2 active frequency.
double engine2Combustion
Engine 2 combustion flag.
double latitudeDeg
Latitude (deg)
double simOnGround
Is aircraft on ground?
double altitudeFt
Altitude (ft)
double comTransmit1
COM1 transmit, means also receiving.
double comReceiveAll
all COMs receiving, or COM:x transmitting or receiving
double comStatus1
COM1 status.
double comStatus2
COM2 status.
double comTransmit2
COM2 transmit, means also receiving.
double flapsHandlePosition
Flaps handle position in percent.
double com2StandbyMHz
COM2 standby frequency.
double elevationFt
Elevation (ft)
double pressureAltitudeM
Pressure altitude (m)
double trueHeadingDeg
True heading (deg)
double rotationVelocityBodyZ
Rotation Velocity Body Z.
double spoilersHandlePosition
Spoilers out? (flag)
double velocityWorldX
Velocity World X.
double comTest1
COM1 test.
double rotationVelocityBodyY
Rotation Velocity Body Y.
double com1ActiveMHz
COM1 active frequency.
double lightLanding
Is landing light on?
double engine1Combustion
Engine 1 combustion flag.
double pitchDeg
Pitch (deg)
double lightTaxi
Is taxi light on?
double numberOfEngines
Number of engines.
double velocityWorldZ
Velocity World Z.
double cgToGroundFt
Static CG to ground (ft)
double com1StandbyMHz
COM1 standby frequency.
double engine4Combustion
Engine 4 combustion flag.
double longitudeDeg
Longitude (deg)
double gearHandlePosition
Gear handle position (flag)
double comTest2
COM2 test.
double engine3Combustion
Engine 3 combustion flag.
double lightStrobe
Is strobe light on?
double transponderCode
Transponder Code.
Struct to trace send ids.
static const TraceFsxSendId & invalid()
Invalid object.
CSimConnectObject simObject
CSimConnectObject at the time of the trace.
#define SWIFT_AUDIT_X(COND, WHERE, WHAT)
A weaker kind of verify.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.