From 42549760edb8b526d90caa5a2edcae64c51d565a Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Fri, 11 Nov 2016 01:08:20 +0100 Subject: [PATCH] refs #789, support for aircraft out of FSX reality bubble * such aircraft will be tried to be added again * removed qeueud adding as it was not solving the problem --- src/blackcore/simulatorcommon.cpp | 18 --- src/blackcore/simulatorcommon.h | 12 +- src/plugins/simulator/fsx/simulatorfsx.cpp | 112 +++++++++++++----- src/plugins/simulator/fsx/simulatorfsx.h | 36 +++--- .../fsx/simulatorfsxsimconnectproc.cpp | 20 +--- 5 files changed, 110 insertions(+), 88 deletions(-) diff --git a/src/blackcore/simulatorcommon.cpp b/src/blackcore/simulatorcommon.cpp index bea4911ac..28d457281 100644 --- a/src/blackcore/simulatorcommon.cpp +++ b/src/blackcore/simulatorcommon.cpp @@ -435,23 +435,6 @@ namespace BlackCore Q_UNUSED(callsign); } - void CSimulatorCommon::ps_queueForAdding(const CSimulatedAircraft &aircraft) - { - m_pendingAircraftToAdd.replaceOrAddByCallsign(aircraft); - QTimer::singleShot(500, this, [ = ] - { - this->physicallyAddNextQueuedAircraft(); - }); - } - - void CSimulatorCommon::physicallyAddNextQueuedAircraft() - { - if (m_pendingAircraftToAdd.isEmpty()) { return; } // delete in meantime - CSimulatedAircraft nextAircraft(m_pendingAircraftToAdd.front()); // normally it should always find a value - m_pendingAircraftToAdd.pop_front(); - this->physicallyAddRemoteAircraft(nextAircraft); - } - void CSimulatorCommon::reset() { m_statsUpdateAircraftCountMs = 0; @@ -463,7 +446,6 @@ namespace BlackCore void CSimulatorCommon::clearAllAircraft() { m_aircraftToAddAgainWhenRemoved.clear(); - m_pendingAircraftToAdd.clear(); } } // namespace diff --git a/src/blackcore/simulatorcommon.h b/src/blackcore/simulatorcommon.h index cb68d48cd..f968f388b 100644 --- a/src/blackcore/simulatorcommon.h +++ b/src/blackcore/simulatorcommon.h @@ -89,7 +89,8 @@ namespace BlackCore protected slots: - //! \name Connected with remote aircraft provider signals { + //! \name Connected with remote aircraft provider signals + //! @{ //! Slow timer used to highlight aircraft, can be used for other things too virtual void ps_oneSecondTimer(); @@ -106,10 +107,6 @@ namespace BlackCore virtual void ps_remoteProviderRemovedAircraft(const BlackMisc::Aviation::CCallsign &callsign); //! @} - //! Add when pending aircraft is added - //! \remark no need to use this if multiple models can be added to simulator at once - void ps_queueForAdding(const BlackMisc::Simulation::CSimulatedAircraft &aircraft); - protected: //! Constructor CSimulatorCommon(const BlackMisc::Simulation::CSimulatorPluginInfo &info, @@ -145,9 +142,6 @@ namespace BlackCore //! Set own model void reverseLookupAndUpdateOwnAircraftModel(const QString &modelString); - //! Add the next qeueud aircraft - void physicallyAddNextQueuedAircraft(); - BlackMisc::IInterpolator *m_interpolator = nullptr; //!< interpolator instance bool m_pausedSimFreezesInterpolation = false; //!< paused simulator will also pause interpolation (so AI aircraft will hold) BlackMisc::Simulation::CSimulatorSetup m_simulatorSetup; //!< setup object @@ -159,7 +153,6 @@ namespace BlackCore // some optional functionality which can be used by the sims as needed BlackMisc::Simulation::CSimulatedAircraftList m_aircraftToAddAgainWhenRemoved; //!< add this model again when removed, normally used to change model - BlackMisc::Simulation::CSimulatedAircraftList m_pendingAircraftToAdd; //!< used with qeued adding, here only one model is added add a time and only after it is confirmed by the sim. the next model is added //! Lookup against DB data static BlackMisc::Simulation::CAircraftModel reverseLookupModel(const BlackMisc::Simulation::CAircraftModel &model); @@ -179,7 +172,6 @@ namespace BlackCore BlackMisc::Aviation::CCallsignSet m_callsignsToBeRendered; //!< callsigns which will be rendered BlackMisc::PhysicalQuantities::CLength m_maxRenderedDistance { 0.0, BlackMisc::PhysicalQuantities::CLengthUnit::nullUnit()}; //!< max.distance for rendering BlackMisc::CConnectionGuard m_remoteAircraftProviderConnections; //!< connected signal/slots - }; } // namespace diff --git a/src/plugins/simulator/fsx/simulatorfsx.cpp b/src/plugins/simulator/fsx/simulatorfsx.cpp index 14c771fed..bb2fdfb9a 100644 --- a/src/plugins/simulator/fsx/simulatorfsx.cpp +++ b/src/plugins/simulator/fsx/simulatorfsx.cpp @@ -51,6 +51,8 @@ namespace BlackSimPlugin Q_ASSERT_X(remoteAircraftProvider, Q_FUNC_INFO, "Missing provider"); Q_ASSERT_X(sApp, Q_FUNC_INFO, "Missing global object"); this->m_simulatorSetup = CFsxSimulatorSetup::getInitialSetup(); + this->m_realityBubbleTimer.setInterval(20 * 1000); + connect(&m_realityBubbleTimer, &QTimer::timeout, this, &CSimulatorFsx::ps_addAircraftCurrentlyOutOfBubble); m_useFsuipc = true; // Temporarily enabled until Simconnect Weather is implemented. this->m_interpolator = new CInterpolatorLinear(remoteAircraftProvider, this); @@ -94,6 +96,7 @@ namespace BlackSimPlugin initEvents(); initDataDefinitionsWhenConnected(); m_simconnectTimerId = startTimer(10); + m_realityBubbleTimer.start(); reloadWeatherSettings(); return true; } @@ -125,6 +128,7 @@ namespace BlackSimPlugin if (callsign.isEmpty()) { return false; } // check if we have to do something + m_outOfRealityBubble.removeByCallsign(callsign); if (m_simConnectObjects.contains(callsign)) { const CSimConnectObject simObj = m_simConnectObjects[callsign]; @@ -143,37 +147,18 @@ namespace BlackSimPlugin } } - if (!m_pendingAircraftToAdd.isEmpty() || m_simConnectObjects.containsPendingAdd()) - { - const CSimConnectObject simObj = m_simConnectObjects[callsign]; - if (simObj.isPendingAdded()) - { - return true; // already pending - } - else - { - // same model, nothing will change, otherwise add again when removed - if (simObj.getAircraft().getModel() != newRemoteAircraft.getModel()) - { - m_aircraftToAddAgainWhenRemoved.push_back(newRemoteAircraft); - } - return false; - } - } - // create AI bool adding = false; const CAircraftModel aircraftModel = newRemoteAircraft.getModel(); CSimulatedAircraft addedAircraft(newRemoteAircraft); if (isConnected()) { - // initial position + // initial position if interpolator has data, otherwise do nothing setInitialAircraftSituation(addedAircraft); // set interpolated data/parts if available const int requestId = m_requestId++; SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxPosition(addedAircraft.getSituation()); const QString modelString(addedAircraft.getModelString()); - const QByteArray m(modelString.toLocal8Bit()); if (m_interpolationRenderingSetup.showSimulatorDebugMessages()) { @@ -181,7 +166,7 @@ namespace BlackSimPlugin CLogMessage(this).debug() << "initial position" << fsxPositionToString(initialPosition); } - HRESULT hr = SimConnect_AICreateNonATCAircraft(m_hSimConnect, m.constData(), qPrintable(callsign.toQString().left(12)), initialPosition, static_cast(requestId)); + HRESULT hr = SimConnect_AICreateNonATCAircraft(m_hSimConnect, qPrintable(modelString), qPrintable(callsign.toQString().left(12)), initialPosition, static_cast(requestId)); if (hr != S_OK) { const CStatusMessage msg = CStatusMessage(this).error("SimConnect, can not create AI traffic: '%1' '%2'") << callsign.toQString() << aircraftModel.getModelString(); @@ -500,8 +485,23 @@ namespace BlackSimPlugin const CCallsign callsign(simObject.getCallsign()); if (!simObject.hasValidRequestAndObjectId() || callsign.isEmpty()) { return false; } + // we know the object has been created. But it can happen it is directly removed afterwards + QTimer::singleShot(500, this, [ = ] { this->ps_deferredSimulatorReportedObjectAdded(callsign); }); + return true; + } + + bool CSimulatorFsx::ps_deferredSimulatorReportedObjectAdded(const CCallsign &callsign) + { + if (callsign.isEmpty()) { return false; } + if (!m_simConnectObjects.contains(callsign)) { return false; } // removed in mean time + + CSimConnectObject &simObject = m_simConnectObjects[callsign]; + if (!simObject.hasValidRequestAndObjectId() || simObject.isPendingRemoved()) { return false; } + Q_ASSERT_X(simObject.isPendingAdded(), Q_FUNC_INFO, "already confirmed"); - m_simConnectObjects[callsign].setConfirmedAdded(true); + simObject.setConfirmedAdded(true); + DWORD objectID = static_cast(simObject.getObjectId()); + if (m_interpolationRenderingSetup.showSimulatorDebugMessages()) { CLogMessage(this).debug() << "Adding AI" << callsign.toQString() << "confirmed" << "id" << static_cast(objectID) << "model" << simObject.getAircraftModelString(); @@ -522,9 +522,10 @@ namespace BlackSimPlugin else { CLogMessage(this).error("Adding AI %1 failed") << callsign.toQString(); + return false; } - const bool updated = this->updateAircraftRendered(simObject.getCallsign(), true); + const bool updated = this->updateAircraftRendered(callsign, true); if (updated) { emit aircraftRenderingChanged(simObject.getAircraft()); @@ -532,6 +533,38 @@ namespace BlackSimPlugin return true; } + void CSimulatorFsx::ps_addAircraftCurrentlyOutOfBubble() + { + if (m_outOfRealityBubble.isEmpty()) { return; } + const CCallsignSet aircraftCallsignsInRange(getAircraftInRangeCallsigns()); + CSimulatedAircraftList toBeAddedAircraft; + CCallsignSet toBeRemovedCallsigns; + for (const CSimulatedAircraft &aircraft : as_const(m_outOfRealityBubble)) + { + Q_ASSERT_X(!aircraft.getCallsign().isEmpty(), Q_FUNC_INFO, "missing callsign"); + if (aircraftCallsignsInRange.contains(aircraft.getCallsign())) + { + toBeAddedAircraft.push_back(aircraft); + } + else + { + toBeRemovedCallsigns.push_back(aircraft.getCallsign()); + } + } + m_outOfRealityBubble.removeByCallsigns(toBeRemovedCallsigns); + + // add aircraft, but non blocking + int t = 100; + for (const CSimulatedAircraft &aircraft : as_const(toBeAddedAircraft)) + { + QTimer::singleShot(t, this, [ = ] + { + this->physicallyAddRemoteAircraft(aircraft); + }); + t += 100; + } + } + bool CSimulatorFsx::simulatorReportedObjectRemoved(DWORD objectID) { const CSimConnectObject simObject = this->m_simConnectObjects.getSimObjectForObjectId(objectID); @@ -542,17 +575,26 @@ namespace BlackSimPlugin bool ok = false; if (simObject.isPendingRemoved()) { - // good case, we can remove object + // good case, object has been removed + // we can remove the sim object } else { // object was removed but not requested by us - CLogMessage(this).warning("Removed %1 from simulator, but was not initiated by us: %1 '%2' object id %3") << callsign.toQString() << simObject.getAircraftModelString() << static_cast(objectID); + // this means we are out of the reality bubble (or something else went wrong) + if (!simObject.getAircraftModelString().isEmpty()) + { + this->m_outOfRealityBubble.push_back(simObject.getAircraft()); + CLogMessage(this).info("Aircraft '%1' '%2' '%3' out of reality bubble") << callsign.toQString() << simObject.getAircraftModelString() << static_cast(objectID); + } + else + { + CLogMessage(this).warning("Removed %1 from simulator, but was not initiated by us: %1 '%2' object id %3") << callsign.toQString() << simObject.getAircraftModelString() << static_cast(objectID); + } } // in all cases we remove const int c = m_simConnectObjects.remove(callsign); - m_pendingAircraftToAdd.removeByCallsign(callsign); ok = c > 0; CLogMessage(this).info("FSX: Removed aircraft '%1'") << simObject.getCallsign().toQString(); @@ -621,7 +663,7 @@ namespace BlackSimPlugin Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "wrong thread"); if (callsign.isEmpty()) { return false; } // can happen if an object is not an aircraft - if (m_pendingAircraftToAdd.removeByCallsign(callsign) > 0) { return true; } // was in queue to be added + m_outOfRealityBubble.removeByCallsign(callsign); if (!m_simConnectObjects.contains(callsign)) { return false; } // already fully removed or not yet added CSimConnectObject &simObject = m_simConnectObjects[callsign]; @@ -629,7 +671,7 @@ namespace BlackSimPlugin if (simObject.isPendingAdded()) { // problem: we try to delete an aircraft just requested to be added - return false; //! \todo improve + return false; //! \fixme improve } simObject.setPendingRemoved(true); @@ -756,7 +798,7 @@ namespace BlackSimPlugin // nothing to do, reset request id and exit if (this->isPaused() && this->m_pausedSimFreezesInterpolation) { return; } // no interpolation while paused - int remoteAircraftNo = this->getAircraftInRangeCount(); + const int remoteAircraftNo = this->getAircraftInRangeCount(); if (remoteAircraftNo < 1) { m_interpolationRequest = 0; return; } // interpolate and send to SIM @@ -861,7 +903,7 @@ namespace BlackSimPlugin ddRemoteAircraftParts.spoilersHandlePosition = newestParts.isSpoilersOut() ? 1.0 : 0.0; ddRemoteAircraftParts.gearHandlePosition = newestParts.isGearDown() ? 1 : 0; ddRemoteAircraftParts.engine1Combustion = newestParts.isEngineOn(1) ? 1 : 0; - ddRemoteAircraftParts.engine2Combustion = newestParts.isEngineOn(2) ? 1 : 0;; + ddRemoteAircraftParts.engine2Combustion = newestParts.isEngineOn(2) ? 1 : 0; ddRemoteAircraftParts.engine3Combustion = newestParts.isEngineOn(3) ? 1 : 0; ddRemoteAircraftParts.engine4Combustion = newestParts.isEngineOn(4) ? 1 : 0; } @@ -999,13 +1041,21 @@ namespace BlackSimPlugin if (m_simconnectTimerId >= 0) { killTimer(m_simconnectTimerId); } m_simConnected = false; m_simSimulating = false; - m_simconnectTimerId = -1; + m_syncDeferredCounter = 0; + m_simconnectTimerId = -1; + m_skipCockpitUpdateCycles = 0; + m_interpolationRequest = 0; + m_interpolationsSkipped = 0; + m_requestId = 1; + m_dispatchErrors = 0; + m_receiveExceptionCount = 0; CSimulatorFsCommon::reset(); } void CSimulatorFsx::clearAllAircraft() { m_simConnectObjects.clear(); + m_outOfRealityBubble.clear(); CSimulatorFsCommon::clearAllAircraft(); } diff --git a/src/plugins/simulator/fsx/simulatorfsx.h b/src/plugins/simulator/fsx/simulatorfsx.h index e9a4b9ce0..a5216eebd 100644 --- a/src/plugins/simulator/fsx/simulatorfsx.h +++ b/src/plugins/simulator/fsx/simulatorfsx.h @@ -130,7 +130,7 @@ namespace BlackSimPlugin //! \copydoc BlackCore::ISimulator::isSimulating virtual bool isSimulating() const override; - //! Timer event (our SimConnect event loop), runs \sa ps_dispatch + //! Timer event (our SimConnect event loop), runs ps_dispatch //! \sa m_simconnectTimerId virtual void timerEvent(QTimerEvent *event) override; @@ -142,6 +142,12 @@ namespace BlackSimPlugin //! \remark kind of cleanup function, in an ideal this should never need to cleanup something BlackMisc::Aviation::CCallsignSet ps_physicallyRemoveAircraftNotInProvider(); + //! Handle that an object has been added + bool ps_deferredSimulatorReportedObjectAdded(const BlackMisc::Aviation::CCallsign &callsign); + + //! Try to add the aircraft currently out of bubble + void ps_addAircraftCurrentlyOutOfBubble(); + private: //! Call this method to declare the simulator connected void setSimConnected(); @@ -200,21 +206,23 @@ namespace BlackSimPlugin static constexpr int SkipUpdateCyclesForCockpit = 10; //!< skip x cycles before updating cockpit again static constexpr int IgnoreReceiveExceptions = 10; //!< skip exceptions when displayed more than x times - bool m_simConnected = false; //!< Is simulator connected? - bool m_simSimulating = false; //!< Simulator running? - bool m_useSbOffsets = true; //!< with SB offsets - int m_syncDeferredCounter = 0; //!< Set when synchronized, used to wait some time - int m_simconnectTimerId = -1; //!< Timer identifier - int m_skipCockpitUpdateCycles = 0; //!< Skip some update cycles to allow changes in simulator cockpit to be set - int m_interpolationRequest = 0; //!< current interpolation request - int m_interpolationsSkipped = 0; //!< number of skipped interpolation request - int m_requestId = 1; //!< request id - int m_dispatchErrors = 0; //!< number of dispatched failed, \sa ps_dispatch - int m_receiveExceptionCount = 0; //!< exceptions - HANDLE m_hSimConnect = nullptr; //!< Handle to SimConnect object + bool m_simConnected = false; //!< Is simulator connected? + bool m_simSimulating = false; //!< Simulator running? + bool m_useSbOffsets = true; //!< with SB offsets + int m_syncDeferredCounter = 0; //!< Set when synchronized, used to wait some time + int m_simconnectTimerId = -1; //!< Timer identifier + int m_skipCockpitUpdateCycles = 0; //!< Skip some update cycles to allow changes in simulator cockpit to be set + int m_interpolationRequest = 0; //!< current interpolation request + int m_interpolationsSkipped = 0; //!< number of skipped interpolation request + int m_requestId = 1; //!< request id + int m_dispatchErrors = 0; //!< number of dispatched failed, \sa ps_dispatch + int m_receiveExceptionCount = 0; //!< exceptions + HANDLE m_hSimConnect = nullptr; //!< Handle to SimConnect object CSimConnectObjects m_simConnectObjects; //!< AI objects and their object / request ids - BlackMisc::Geo::CCoordinateGeodetic m_lastWeatherPosition; //!< Own aircraft position at which weather was fetched and injected last + BlackMisc::Simulation::CSimulatedAircraftList m_outOfRealityBubble; //!< aircraft removed by FSX because they are out of reality bubble + BlackMisc::Geo::CCoordinateGeodetic m_lastWeatherPosition; //!< Own aircraft position at which weather was fetched and injected last BlackMisc::CSetting m_weatherScenarioSettings { this, &CSimulatorFsx::reloadWeatherSettings }; + QTimer m_realityBubbleTimer { this }; //!< updating of aircraft out of reality bubble }; //! Listener for FSX diff --git a/src/plugins/simulator/fsx/simulatorfsxsimconnectproc.cpp b/src/plugins/simulator/fsx/simulatorfsxsimconnectproc.cpp index 0118983a3..3fda291dc 100644 --- a/src/plugins/simulator/fsx/simulatorfsxsimconnectproc.cpp +++ b/src/plugins/simulator/fsx/simulatorfsxsimconnectproc.cpp @@ -50,34 +50,25 @@ namespace BlackSimPlugin } case SIMCONNECT_RECV_ID_EXCEPTION: { - if (!simulatorFsx->stillDisplayReceiveExceptions()) - { - break; - } - + if (!simulatorFsx->stillDisplayReceiveExceptions()) { break; } SIMCONNECT_RECV_EXCEPTION *exception = (SIMCONNECT_RECV_EXCEPTION *)pData; - QString ex; const int exceptionId = static_cast(exception->dwException); const int sendId = static_cast(exception->dwSendID); const int index = static_cast(exception->dwIndex); const int data = static_cast(cbData); + QString ex; ex.sprintf("Exception=%d SendID=%d Index=%d cbData=%d", exceptionId, sendId, index, data); - switch (exceptionId) { case SIMCONNECT_EXCEPTION_OPERATION_INVALID_FOR_OBJECT_TYPE: + break; case SIMCONNECT_EXCEPTION_UNRECOGNIZED_ID: - { - //! \fixme do not know how to obtain the object id which failed. Can I get it? - } break; default: break; } - - CLogMessage(simulatorFsx).error("Caught FSX simConnect exception: %1 %2") - << CSimConnectUtilities::simConnectExceptionToString((SIMCONNECT_EXCEPTION)exception->dwException) - << ex; + CLogMessage(simulatorFsx).warning("Caught FSX simConnect exception: %1 %2") + << CSimConnectUtilities::simConnectExceptionToString((SIMCONNECT_EXCEPTION)exception->dwException) << ex; break; } case SIMCONNECT_RECV_ID_QUIT: @@ -135,7 +126,6 @@ namespace BlackSimPlugin { case SystemEventObjectAdded: // added in SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID - // adding here cause trouble break; case SystemEventObjectRemoved: simulatorFsx->simulatorReportedObjectRemoved(objectID);