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
This commit is contained in:
Klaus Basan
2016-11-11 01:08:20 +01:00
parent 356e91c22f
commit 42549760ed
5 changed files with 110 additions and 88 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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<SIMCONNECT_DATA_REQUEST_ID>(requestId));
HRESULT hr = SimConnect_AICreateNonATCAircraft(m_hSimConnect, qPrintable(modelString), qPrintable(callsign.toQString().left(12)), initialPosition, static_cast<SIMCONNECT_DATA_REQUEST_ID>(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<DWORD>(simObject.getObjectId());
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
{
CLogMessage(this).debug() << "Adding AI" << callsign.toQString() << "confirmed" << "id" << static_cast<int>(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<int>(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<int>(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<int>(objectID);
}
}
// in all cases we remove
const int c = m_simConnectObjects.remove(callsign);
m_pendingAircraftToAdd.removeByCallsign(callsign);
ok = c > 0;
CLogMessage(this).info("FSX: Removed aircraft '%1'") << simObject.getCallsign().toQString();
@@ -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();
}

View File

@@ -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<BlackCore::Simulator::TSelectedWeatherScenario> m_weatherScenarioSettings { this, &CSimulatorFsx::reloadWeatherSettings };
QTimer m_realityBubbleTimer { this }; //!< updating of aircraft out of reality bubble
};
//! Listener for FSX

View File

@@ -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<int>(exception->dwException);
const int sendId = static_cast<int>(exception->dwSendID);
const int index = static_cast<int>(exception->dwIndex);
const int data = static_cast<int>(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);