mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-31 04:25:35 +08:00
Ref T27, improved adding of sim objects
* only add one object at a time * only query object values (from sim) when object is confirmed * better debug logging (can be switched on) * physicallyAddRemoteAircraftImpl for better tracing of added objects * wait until light state is available
This commit is contained in:
committed by
Mathew Sutcliffe
parent
bd67824ce6
commit
645faf8373
@@ -52,7 +52,7 @@ namespace BlackSimPlugin
|
||||
Q_ASSERT_X(remoteAircraftProvider, Q_FUNC_INFO, "Missing provider");
|
||||
Q_ASSERT_X(sApp, Q_FUNC_INFO, "Missing global object");
|
||||
m_addPendingAircraftTimer.setInterval(AddPendingAircraftIntervalMs);
|
||||
connect(&m_addPendingAircraftTimer, &QTimer::timeout, this, &CSimulatorFsxCommon::addPendingAircraft);
|
||||
connect(&m_addPendingAircraftTimer, &QTimer::timeout, this, &CSimulatorFsxCommon::addPendingAircraftByTimer);
|
||||
|
||||
m_useFsuipc = false;
|
||||
m_defaultModel =
|
||||
@@ -95,7 +95,8 @@ namespace BlackSimPlugin
|
||||
initEvents();
|
||||
initDataDefinitionsWhenConnected();
|
||||
m_simConnectTimerId = startTimer(DispatchIntervalMs);
|
||||
m_addPendingAircraftTimer.start();
|
||||
// do not start m_addPendingAircraftTimer here, it will be started when object was added
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -104,6 +105,7 @@ namespace BlackSimPlugin
|
||||
if (!m_simConnected) { return true; }
|
||||
if (m_simConnectTimerId >= 0) { killTimer(m_simConnectTimerId); }
|
||||
m_simConnectTimerId = -1;
|
||||
this->onSimStopped(); // treat as stopped
|
||||
if (m_hSimConnect)
|
||||
{
|
||||
SimConnect_Close(m_hSimConnect);
|
||||
@@ -119,72 +121,7 @@ namespace BlackSimPlugin
|
||||
|
||||
bool CSimulatorFsxCommon::physicallyAddRemoteAircraft(const CSimulatedAircraft &newRemoteAircraft)
|
||||
{
|
||||
const CCallsign callsign(newRemoteAircraft.getCallsign());
|
||||
|
||||
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "thread");
|
||||
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
|
||||
Q_ASSERT_X(newRemoteAircraft.hasModelString(), Q_FUNC_INFO, "missing model string");
|
||||
if (callsign.isEmpty()) { return false; }
|
||||
|
||||
// check if we have to do something
|
||||
m_addPendingAircraft.removeByCallsign(callsign);
|
||||
if (m_simConnectObjects.contains(callsign))
|
||||
{
|
||||
const CSimConnectObject simObj = m_simConnectObjects[callsign];
|
||||
if (simObj.isPendingAdded())
|
||||
{
|
||||
return true; // already pending
|
||||
}
|
||||
else
|
||||
{
|
||||
// same model, nothing will change, otherwise add again when removed
|
||||
if (simObj.getAircraft().getModel() != newRemoteAircraft.getModel())
|
||||
{
|
||||
m_aircraftToAddAgainWhenRemoved.push_back(newRemoteAircraft);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// create AI
|
||||
bool adding = false;
|
||||
const CAircraftModel aircraftModel = newRemoteAircraft.getModel();
|
||||
CSimulatedAircraft addedAircraft(newRemoteAircraft);
|
||||
if (isConnected())
|
||||
{
|
||||
const DWORD requestId = obtainRequestIdSimData();
|
||||
SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxPosition(addedAircraft.getSituation());
|
||||
const QString modelString(addedAircraft.getModelString());
|
||||
|
||||
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
|
||||
{
|
||||
CLogMessage(this).debug() << "physicallyAddRemoteAircraft" << callsign.toQString() << "request" << requestId << "model" << modelString;
|
||||
CLogMessage(this).debug() << "initial position" << fsxPositionToString(initialPosition);
|
||||
}
|
||||
|
||||
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();
|
||||
CLogMessage::preformatted(msg);
|
||||
emit physicallyAddingRemoteModelFailed(addedAircraft, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we will request a new aircraft by request ID, later we will receive its object id
|
||||
// so far this object id is -1
|
||||
addedAircraft.setRendered(false);
|
||||
CSimConnectObject simObject(addedAircraft, requestId, &m_interpolationLogger);
|
||||
if (addedAircraft.isPartsSynchronized()) { simObject.addAircraftParts(addedAircraft.getParts()); }
|
||||
m_simConnectObjects.insert(callsign, simObject);
|
||||
adding = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLogMessage(this).warning("FSX: Not connected, not added aircraft '%1' '%2'") << callsign.toQString() << aircraftModel.getModelString();
|
||||
}
|
||||
return adding;
|
||||
return this->physicallyAddRemoteAircraftImpl(newRemoteAircraft, ExternalCall);
|
||||
}
|
||||
|
||||
bool CSimulatorFsxCommon::updateOwnSimulatorCockpit(const CSimulatedAircraft &ownAircraft, const CIdentifier &originator)
|
||||
@@ -330,8 +267,18 @@ namespace BlackSimPlugin
|
||||
}
|
||||
|
||||
void CSimulatorFsxCommon::onSimRunning()
|
||||
{
|
||||
QTimer::singleShot(DeferSimulatingFlagMs, this, [ = ]
|
||||
{
|
||||
m_simulatingChangedTs = QDateTime::currentMSecsSinceEpoch();
|
||||
this->onSimRunningDefered(m_simulatingChangedTs);
|
||||
});
|
||||
}
|
||||
|
||||
void CSimulatorFsxCommon::onSimRunningDefered(qint64 referenceTs)
|
||||
{
|
||||
if (m_simSimulating) { return; }
|
||||
if (referenceTs != m_simulatingChangedTs) { return; } // changed, so no longer valid
|
||||
m_simSimulating = true; // only place where this should be set to true
|
||||
m_simConnected = true;
|
||||
HRESULT hr = SimConnect_RequestDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::RequestOwnAircraft,
|
||||
@@ -372,6 +319,7 @@ namespace BlackSimPlugin
|
||||
// stopping events in FSX: Load menu, weather and season
|
||||
const int oldStatus = getSimulatorStatus();
|
||||
m_simSimulating = false;
|
||||
m_simulatingChangedTs = QDateTime::currentMSecsSinceEpoch();
|
||||
emitSimulatorCombinedStatus(oldStatus);
|
||||
}
|
||||
|
||||
@@ -383,6 +331,7 @@ namespace BlackSimPlugin
|
||||
void CSimulatorFsxCommon::onSimExit()
|
||||
{
|
||||
// reset complete state, we are going down
|
||||
m_simulatingChangedTs = QDateTime::currentMSecsSinceEpoch();
|
||||
disconnectFrom();
|
||||
}
|
||||
|
||||
@@ -402,7 +351,7 @@ namespace BlackSimPlugin
|
||||
|
||||
if (simulatorOwnAircraft.pitch < -90.0 || simulatorOwnAircraft.pitch >= 90.0)
|
||||
{
|
||||
CLogMessage(this).warning("FSX: Pitch value out of limits: %1") << simulatorOwnAircraft.pitch;
|
||||
CLogMessage(this).warning("FSX: Pitch value (own aircraft) out of limits: %1") << simulatorOwnAircraft.pitch;
|
||||
}
|
||||
BlackMisc::Aviation::CAircraftSituation aircraftSituation;
|
||||
aircraftSituation.setPosition(position);
|
||||
@@ -541,61 +490,120 @@ namespace BlackSimPlugin
|
||||
this->updateCockpit(myAircraft.getCom1System(), myAircraft.getCom2System(), xpdr, this->identifier());
|
||||
}
|
||||
|
||||
bool CSimulatorFsxCommon::simulatorReportedObjectAdded(DWORD objectID)
|
||||
bool CSimulatorFsxCommon::simulatorReportedObjectAdded(DWORD objectId)
|
||||
{
|
||||
const CSimConnectObject simObject = this->m_simConnectObjects.getSimObjectForObjectId(objectID);
|
||||
const CSimConnectObject simObject = this->m_simConnectObjects.getSimObjectForObjectId(objectId);
|
||||
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->deferredSimulatorReportedObjectAdded(callsign); });
|
||||
QTimer::singleShot(500, this, [ = ]
|
||||
{
|
||||
// also triggers new add
|
||||
this->verifyAddedRemoteAircraft(simObject.getAircraft());
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSimulatorFsxCommon::deferredSimulatorReportedObjectAdded(const CCallsign &callsign)
|
||||
void CSimulatorFsxCommon::verifyAddedRemoteAircraft(const CSimulatedAircraft &remoteAircraftIn)
|
||||
{
|
||||
if (callsign.isEmpty()) { return false; }
|
||||
if (!m_simConnectObjects.contains(callsign)) { return false; } // removed in mean time
|
||||
CStatusMessage msg;
|
||||
CSimulatedAircraft remoteAircraft = remoteAircraftIn;
|
||||
const CCallsign callsign(remoteAircraft.getCallsign());
|
||||
|
||||
CSimConnectObject &simObject = m_simConnectObjects[callsign];
|
||||
if (!simObject.hasValidRequestAndObjectId() || simObject.isPendingRemoved()) { return false; }
|
||||
|
||||
Q_ASSERT_X(simObject.isPendingAdded(), Q_FUNC_INFO, "already confirmed");
|
||||
simObject.setConfirmedAdded(true);
|
||||
const DWORD objectId = simObject.getObjectId();
|
||||
|
||||
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
|
||||
do
|
||||
{
|
||||
CLogMessage(this).debug() << "Adding AI" << callsign.toQString() << "confirmed" << "id" << objectId << "model" << simObject.getAircraftModelString();
|
||||
// no callsign
|
||||
if (callsign.isEmpty())
|
||||
{
|
||||
msg = CLogMessage(this).error("Cannot confirm AI object, empty callsign");
|
||||
break;
|
||||
}
|
||||
|
||||
// removed in meantime
|
||||
const bool aircraftStillInRange = this->isAircraftInRange(callsign);
|
||||
if (!m_simConnectObjects.contains(callsign))
|
||||
{
|
||||
if (aircraftStillInRange)
|
||||
{
|
||||
msg = CLogMessage(this).warning("Callsign '%1' removed in meantime, but still in range") << callsign.toQString();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->removeAsPendingAndAddAgain(callsign);
|
||||
msg = CLogMessage(this).info("Callsign '%1' removed in meantime and no longer in range") << callsign.toQString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
CSimConnectObject &simObject = m_simConnectObjects[callsign];
|
||||
remoteAircraft = simObject.getAircraft(); // update, if something has changed
|
||||
|
||||
if (!simObject.hasValidRequestAndObjectId() || simObject.isPendingRemoved())
|
||||
{
|
||||
msg = CStatusMessage(this).warning("Object for callsign '%1'/id: %2 removed in meantime/invalid") << callsign.toQString() << simObject.getObjectId();
|
||||
break;
|
||||
}
|
||||
|
||||
Q_ASSERT_X(simObject.isPendingAdded(), Q_FUNC_INFO, "already confirmed, this should be the only place");
|
||||
simObject.setConfirmedAdded(true);
|
||||
|
||||
// P3D also has SimConnect_AIReleaseControlEx;
|
||||
const DWORD requestId = obtainRequestIdSimData();
|
||||
const DWORD objectId = simObject.getObjectId();
|
||||
HRESULT hr = SimConnect_AIReleaseControl(m_hSimConnect, objectId, static_cast<SIMCONNECT_DATA_REQUEST_ID>(requestId));
|
||||
hr += SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventFreezeLat, 1,
|
||||
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
hr += SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventFreezeAlt, 1,
|
||||
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
hr += SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventFreezeAtt, 1,
|
||||
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
|
||||
if (hr != S_OK)
|
||||
{
|
||||
msg = CStatusMessage(this).error("Cannot confirm object %1, cs: '%2' model: '%3'") << objectId << remoteAircraft.getCallsignAsString() << remoteAircraft.getModelString();
|
||||
break;
|
||||
}
|
||||
|
||||
// request data on object
|
||||
this->requestDataForSimObject(simObject);
|
||||
this->requestLightsForSimObject(simObject);
|
||||
|
||||
this->removeAsPendingAndAddAgain(callsign); // no longer try to add
|
||||
const bool updated = this->updateAircraftRendered(callsign, true);
|
||||
if (updated)
|
||||
{
|
||||
emit aircraftRenderingChanged(simObject.getAircraft());
|
||||
if (this->showDebugLogMessage()) { this->debugLogMessage(Q_FUNC_INFO, QString("Cs: '%1' model: '%2' verified, request/object id: %3 %4").arg(callsign.toQString(), remoteAircraft.getModelString()).arg(requestId).arg(objectId)); }
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
|
||||
// log errors and emit signal
|
||||
if (!msg.isEmpty())
|
||||
{
|
||||
CLogMessage::preformatted(msg);
|
||||
emit this->physicallyAddingRemoteModelFailed(CSimulatedAircraft(), msg);
|
||||
}
|
||||
|
||||
// P3D also has SimConnect_AIReleaseControlEx;
|
||||
const DWORD requestId = obtainRequestIdSimData();
|
||||
HRESULT hr = SimConnect_AIReleaseControl(m_hSimConnect, objectId, static_cast<SIMCONNECT_DATA_REQUEST_ID>(requestId));
|
||||
if (hr == S_OK)
|
||||
// trigger new adding
|
||||
if (!m_addPendingAircraft.isEmpty())
|
||||
{
|
||||
SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventFreezeLat, 1,
|
||||
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventFreezeAlt, 1,
|
||||
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventFreezeAtt, 1,
|
||||
SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
this->addPendingAircraftAfterAdded();
|
||||
}
|
||||
else
|
||||
{
|
||||
CLogMessage(this).error("Adding AI %1 failed") << callsign.toQString();
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool updated = this->updateAircraftRendered(callsign, true);
|
||||
if (updated)
|
||||
{
|
||||
emit aircraftRenderingChanged(simObject.getAircraft());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSimulatorFsxCommon::addPendingAircraft()
|
||||
void CSimulatorFsxCommon::addPendingAircraftByTimer()
|
||||
{
|
||||
this->addPendingAircraft(AddByTimer);
|
||||
}
|
||||
|
||||
void CSimulatorFsxCommon::addPendingAircraftAfterAdded()
|
||||
{
|
||||
this->addPendingAircraft(AddAfterAdded);
|
||||
}
|
||||
|
||||
void CSimulatorFsxCommon::addPendingAircraft(AircraftAddMode mode)
|
||||
{
|
||||
if (m_addPendingAircraft.isEmpty()) { return; }
|
||||
const CCallsignSet aircraftCallsignsInRange(getAircraftInRangeCallsigns());
|
||||
@@ -613,20 +621,29 @@ namespace BlackSimPlugin
|
||||
toBeRemovedCallsigns.push_back(aircraft.getCallsign());
|
||||
}
|
||||
}
|
||||
m_addPendingAircraft.removeByCallsigns(toBeRemovedCallsigns);
|
||||
|
||||
// add aircraft, but non blocking
|
||||
int t = 100;
|
||||
for (const CSimulatedAircraft &aircraft : as_const(toBeAddedAircraft))
|
||||
// no longer required to be added
|
||||
m_addPendingAircraft.removeByCallsigns(toBeRemovedCallsigns);
|
||||
m_aircraftToAddAgainWhenRemoved.removeByCallsigns(toBeRemovedCallsigns);
|
||||
|
||||
// add aircraft, but "non blocking"
|
||||
if (!toBeAddedAircraft.isEmpty())
|
||||
{
|
||||
QTimer::singleShot(t, this, [ = ]
|
||||
const CSimulatedAircraft nextPendingAircraft(m_addPendingAircraft.front());
|
||||
QTimer::singleShot(100, this, [ = ]
|
||||
{
|
||||
this->physicallyAddRemoteAircraft(aircraft);
|
||||
this->physicallyAddRemoteAircraftImpl(nextPendingAircraft, mode);
|
||||
});
|
||||
t += 100;
|
||||
}
|
||||
}
|
||||
|
||||
void CSimulatorFsxCommon::removeAsPendingAndAddAgain(const CCallsign &callsign)
|
||||
{
|
||||
if (callsign.isEmpty()) { return; }
|
||||
this->m_addPendingAircraft.removeByCallsign(callsign);
|
||||
this->m_aircraftToAddAgainWhenRemoved.removeByCallsign(callsign);
|
||||
}
|
||||
|
||||
bool CSimulatorFsxCommon::simulatorReportedObjectRemoved(DWORD objectID)
|
||||
{
|
||||
const CSimConnectObject simObject = this->m_simConnectObjects.getSimObjectForObjectId(objectID);
|
||||
@@ -650,7 +667,7 @@ namespace BlackSimPlugin
|
||||
if (!simObject.getAircraftModelString().isEmpty())
|
||||
{
|
||||
this->m_addPendingAircraft.push_back(simObject.getAircraft());
|
||||
CLogMessage(this).info("Aircraft removed, '%1' '%2' object id '%3' out of reality bubble or other reason") << callsign.toQString() << simObject.getAircraftModelString() << objectID;
|
||||
CLogMessage(this).warning("Aircraft removed, '%1' '%2' object id '%3' out of reality bubble or other reason") << callsign.toQString() << simObject.getAircraftModelString() << objectID;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -671,14 +688,18 @@ namespace BlackSimPlugin
|
||||
if (m_aircraftToAddAgainWhenRemoved.containsCallsign(callsign))
|
||||
{
|
||||
const CSimulatedAircraft aircraftAddAgain = m_aircraftToAddAgainWhenRemoved.findFirstByCallsign(callsign);
|
||||
QTimer::singleShot(1000, this, [ = ] { this->physicallyAddRemoteAircraft(aircraftAddAgain); });
|
||||
m_aircraftToAddAgainWhenRemoved.removeByCallsign(callsign);
|
||||
QTimer::singleShot(1000, this, [ = ]
|
||||
{
|
||||
this->physicallyAddRemoteAircraftImpl(aircraftAddAgain, AddedAfterRemoved);
|
||||
});
|
||||
}
|
||||
return ok;
|
||||
return removed;
|
||||
}
|
||||
|
||||
bool CSimulatorFsxCommon::setSimConnectObjectId(DWORD requestID, DWORD objectID)
|
||||
bool CSimulatorFsxCommon::setSimConnectObjectId(DWORD requestId, DWORD objectId)
|
||||
{
|
||||
return this->m_simConnectObjects.setSimConnectObjectIdForRequestId(requestID, objectID, true);
|
||||
return this->m_simConnectObjects.setSimConnectObjectIdForRequestId(requestId, objectId, true);
|
||||
}
|
||||
|
||||
bool CSimulatorFsxCommon::setCurrentLights(const CCallsign &callsign, const CAircraftLights &lights)
|
||||
@@ -701,9 +722,28 @@ namespace BlackSimPlugin
|
||||
dispatch();
|
||||
}
|
||||
|
||||
const QString &CSimulatorFsxCommon::modeToString(CSimulatorFsxCommon::AircraftAddMode mode)
|
||||
{
|
||||
static const QString e("external call");
|
||||
static const QString pt("add pending by timer");
|
||||
static const QString oa("add pending after object added");
|
||||
static const QString ar("add again after removed");
|
||||
static const QString dontKnow("???");
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case ExternalCall: return e;
|
||||
case AddByTimer: return pt;
|
||||
case AddAfterAdded: return oa;
|
||||
case AddedAfterRemoved: return ar;
|
||||
default: break;
|
||||
}
|
||||
return dontKnow;
|
||||
}
|
||||
|
||||
void CSimulatorFsxCommon::dispatch()
|
||||
{
|
||||
HRESULT hr = SimConnect_CallDispatch(m_hSimConnect, SimConnectProc, this);
|
||||
const HRESULT hr = SimConnect_CallDispatch(m_hSimConnect, SimConnectProc, this);
|
||||
if (hr != S_OK)
|
||||
{
|
||||
m_dispatchErrors++;
|
||||
@@ -734,13 +774,95 @@ namespace BlackSimPlugin
|
||||
}
|
||||
}
|
||||
|
||||
bool CSimulatorFsxCommon::physicallyAddRemoteAircraftImpl(const CSimulatedAircraft &newRemoteAircraft, CSimulatorFsxCommon::AircraftAddMode addMode)
|
||||
{
|
||||
const CCallsign callsign(newRemoteAircraft.getCallsign());
|
||||
|
||||
// entry checks
|
||||
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "thread");
|
||||
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
|
||||
Q_ASSERT_X(newRemoteAircraft.hasModelString(), Q_FUNC_INFO, "missing model string");
|
||||
|
||||
// reset timer
|
||||
m_addPendingAircraftTimer.start(AddPendingAircraftIntervalMs); // restart
|
||||
|
||||
const bool hasPendingAdded = m_simConnectObjects.containsPendingAdded();
|
||||
const bool canAdd = m_simSimulating && m_simConnected && !hasPendingAdded;
|
||||
|
||||
Q_ASSERT_X(!hasPendingAdded || m_simConnectObjects.countPendingAdded() < 2, Q_FUNC_INFO, "There must be only 0..1 pending objects");
|
||||
if (this->showDebugLogMessage())
|
||||
{
|
||||
this->debugLogMessage(Q_FUNC_INFO, QString("Cs: '%1' mode: '%2' model: '%3'").arg(newRemoteAircraft.getCallsignAsString(), modeToString(addMode), newRemoteAircraft.getModelString()));
|
||||
this->debugLogMessage(Q_FUNC_INFO, QString("Cs: '%1' pending callsigns: '%2', pending objects: '%3'").arg(newRemoteAircraft.getCallsignAsString(), m_addPendingAircraft.getCallsignStrings().join(", "), m_simConnectObjects.getPendingAddedCallsigns().getCallsignStrings().join(", ")));
|
||||
}
|
||||
|
||||
// do we need to remove/add again because something has changed
|
||||
if (m_simConnectObjects.contains(callsign))
|
||||
{
|
||||
const CSimConnectObject simObj = m_simConnectObjects[callsign];
|
||||
const QString newModelString(newRemoteAircraft.getModelString());
|
||||
const QString simObjModelString(simObj.getAircraftModelString());
|
||||
const bool sameModel = (simObjModelString == newModelString); // compare on string only (other attributes might change such as mode)
|
||||
|
||||
// same model, nothing will change, otherwise add again when removed
|
||||
if (sameModel)
|
||||
{
|
||||
if (this->showDebugLogMessage()) { this->debugLogMessage(Q_FUNC_INFO, QString("Cs: '%1' re-added same model '%2'").arg(newRemoteAircraft.getCallsignAsString(), newModelString)); }
|
||||
return true;
|
||||
}
|
||||
|
||||
this->physicallyRemoveRemoteAircraft(newRemoteAircraft.getCallsign());
|
||||
m_aircraftToAddAgainWhenRemoved.replaceOrAddByCallsign(newRemoteAircraft);
|
||||
if (this->showDebugLogMessage()) { this->debugLogMessage(Q_FUNC_INFO, QString("Cs: '%1' re-added changed model '%2', will be added again").arg(newRemoteAircraft.getCallsignAsString(), newModelString)); }
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if we can add, do not add if simulator is stopped or other objects pending
|
||||
if (!canAdd)
|
||||
{
|
||||
m_addPendingAircraft.replaceOrAddByCallsign(newRemoteAircraft);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->removeAsPendingAndAddAgain(callsign);
|
||||
|
||||
// create AI
|
||||
bool adding = false;
|
||||
const CAircraftModel aircraftModel = newRemoteAircraft.getModel();
|
||||
CSimulatedAircraft addedAircraft(newRemoteAircraft);
|
||||
|
||||
const DWORD requestId = obtainRequestIdSimData();
|
||||
SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxPosition(addedAircraft.getSituation());
|
||||
const QString modelString(addedAircraft.getModelString());
|
||||
if (this->showDebugLogMessage()) { this->debugLogMessage(Q_FUNC_INFO, QString("Cs: '%1' model: '%2' request: %3, init pos: %4").arg(callsign.toQString(), modelString).arg(requestId).arg(fsxPositionToString(initialPosition))); }
|
||||
|
||||
const 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();
|
||||
CLogMessage::preformatted(msg);
|
||||
emit physicallyAddingRemoteModelFailed(addedAircraft, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we will request a new aircraft by request ID, later we will receive its object id
|
||||
// so far this object id is -1
|
||||
addedAircraft.setRendered(false);
|
||||
CSimConnectObject simObject(addedAircraft, requestId, &m_interpolationLogger);
|
||||
if (addedAircraft.isPartsSynchronized()) { simObject.addAircraftParts(addedAircraft.getParts()); }
|
||||
m_simConnectObjects.insert(callsign, simObject);
|
||||
adding = true;
|
||||
}
|
||||
return adding;
|
||||
}
|
||||
|
||||
bool CSimulatorFsxCommon::physicallyRemoveRemoteAircraft(const CCallsign &callsign)
|
||||
{
|
||||
// only remove from sim
|
||||
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
|
||||
|
||||
m_addPendingAircraft.removeByCallsign(callsign);
|
||||
this->removeAsPendingAndAddAgain(callsign);
|
||||
if (!m_simConnectObjects.contains(callsign)) { return false; } // already fully removed or not yet added
|
||||
|
||||
CSimConnectObject &simObject = m_simConnectObjects[callsign];
|
||||
@@ -748,21 +870,23 @@ namespace BlackSimPlugin
|
||||
if (simObject.isPendingAdded())
|
||||
{
|
||||
// problem: we try to delete an aircraft just requested to be added
|
||||
return false; //! \fixme improve, since this scenario is not really covered
|
||||
// best solution so far, call remove again with a delays
|
||||
QTimer::singleShot(2000, this, [ = ]
|
||||
{
|
||||
this->physicallyRemoveRemoteAircraft(callsign);
|
||||
});
|
||||
return false; // not yet deleted
|
||||
}
|
||||
|
||||
simObject.setPendingRemoved(true);
|
||||
if (m_interpolationRenderingSetup.showSimulatorDebugMessages())
|
||||
{
|
||||
CLogMessage(this).debug() << "physicallyRemoveRemoteAircraft" << callsign.toQString();
|
||||
}
|
||||
if (this->showDebugLogMessage()) { this->debugLogMessage(Q_FUNC_INFO, QString("Cs: '%1' request/object id: %2/%3").arg(callsign.toQString()).arg(simObject.getRequestId()).arg(simObject.getObjectId())); }
|
||||
|
||||
// call in SIM
|
||||
SimConnect_AIRemoveObject(m_hSimConnect, static_cast<SIMCONNECT_OBJECT_ID>(simObject.getObjectId()), static_cast<SIMCONNECT_DATA_REQUEST_ID>(m_requestIdSimData++));
|
||||
m_hints.remove(simObject.getCallsign());
|
||||
|
||||
// mark in provider
|
||||
bool updated = updateAircraftRendered(callsign, false);
|
||||
const bool updated = updateAircraftRendered(callsign, false);
|
||||
if (updated)
|
||||
{
|
||||
CSimulatedAircraft aircraft(simObject.getAircraft());
|
||||
@@ -911,6 +1035,7 @@ namespace BlackSimPlugin
|
||||
// happening if aircraft is not yet added to simulator or to be deleted
|
||||
if (simObj.isPendingAdded()) { continue; }
|
||||
if (simObj.isPendingRemoved()) { continue; }
|
||||
if (!simObj.hasCurrentLightsInSimulator()) { continue; } // wait until we have light state
|
||||
|
||||
const CCallsign callsign(simObj.getCallsign());
|
||||
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign");
|
||||
@@ -1091,7 +1216,8 @@ namespace BlackSimPlugin
|
||||
SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventLandingLightsSet, lights.isLandingOn() ? 1.0 : 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
SimConnect_TransmitClientEvent(m_hSimConnect, objectId, EventStrobesSet, lights.isStrobeOn() ? 1.0 : 0.0, SIMCONNECT_GROUP_PRIORITY_HIGHEST, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
|
||||
// lights we need to toggle (risk with quickly changing values that we accidentally toggle back)
|
||||
// lights we need to toggle
|
||||
// (potential risk with quickly changing values that we accidentally toggle back, also we need the light state before we can toggle)
|
||||
sendToggledLightsToSimulator(simObj, lights);
|
||||
|
||||
// done
|
||||
@@ -1144,15 +1270,17 @@ namespace BlackSimPlugin
|
||||
return;
|
||||
}
|
||||
|
||||
// missing lights info from simulator
|
||||
CLogMessage(this).info("Missing light state for '%1'") << callsign;
|
||||
QTimer::singleShot(2500, this, [ = ]
|
||||
// missing lights info from simulator so far
|
||||
if (this->showDebugLogMessage()) { this->debugLogMessage(Q_FUNC_INFO, QString("Missing light state in simulator for '%1', model '%2'").arg(callsign.asString(), simObj.getAircraftModelString())); }
|
||||
|
||||
QTimer::singleShot(DeferResendingLights, this, [ = ]
|
||||
{
|
||||
if (!m_simConnectObjects.contains(callsign)) { return; }
|
||||
const CSimConnectObject currentSimObj = m_simConnectObjects[callsign];
|
||||
if (!currentSimObj.hasValidRequestAndObjectId()) { return; } // stale
|
||||
if (lightsWanted != currentSimObj.getLightsAsSent()) { return; } // changed in between
|
||||
sendToggledLightsToSimulator(currentSimObj, lightsWanted, true);
|
||||
if (lightsWanted != currentSimObj.getLightsAsSent()) { return; } // changed in between, so another call sendToggledLightsToSimulator is pending
|
||||
if (this->showDebugLogMessage()) { this->debugLogMessage(Q_FUNC_INFO, QString("Resending light state for '%1', model '%2'").arg(callsign.asString(), simObj.getAircraftModelString())); }
|
||||
this->sendToggledLightsToSimulator(currentSimObj, lightsWanted, true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1276,7 +1404,8 @@ namespace BlackSimPlugin
|
||||
void CSimulatorFsxCommon::reset()
|
||||
{
|
||||
if (m_simConnectTimerId >= 0) { killTimer(m_simConnectTimerId); }
|
||||
m_simConnectTimerId = -1;
|
||||
m_simConnectTimerId = -1;
|
||||
m_simulatingChangedTs = -1;
|
||||
m_simConnected = false;
|
||||
m_simSimulating = false;
|
||||
m_syncDeferredCounter = 0;
|
||||
@@ -1309,7 +1438,7 @@ namespace BlackSimPlugin
|
||||
|
||||
QString CSimulatorFsxCommon::fsxPositionToString(const SIMCONNECT_DATA_INITPOSITION &position)
|
||||
{
|
||||
const QString positionStr("Lat: %1 lng: %2 alt: %3ft pitch: %4 bank: %5 hdg: %6 airspeed: %7kts onGround: %8");
|
||||
const QString positionStr("Lat: %1deg lng: %2deg alt: %3ft pitch: %4deg bank: %5deg hdg: %6deg airspeed: %7kts onGround: %8");
|
||||
return positionStr.
|
||||
arg(position.Latitude).arg(position.Longitude).arg(position.Altitude).
|
||||
arg(position.Pitch).arg(position.Bank).arg(position.Heading).arg(position.Airspeed).arg(position.OnGround);
|
||||
@@ -1330,6 +1459,8 @@ namespace BlackSimPlugin
|
||||
{
|
||||
physicallyRemoveRemoteAircraft(callsign);
|
||||
}
|
||||
|
||||
if (this->showDebugLogMessage()) { this->debugLogMessage(Q_FUNC_INFO, QString("Cs: '%1'").arg(toBeRemoved.toStringList().join(", "))); }
|
||||
return toBeRemoved;
|
||||
}
|
||||
|
||||
|
||||
@@ -143,19 +143,45 @@ namespace BlackSimPlugin
|
||||
virtual void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private:
|
||||
//! Reason for adding an aircraft
|
||||
enum AircraftAddMode
|
||||
{
|
||||
ExternalCall, //!< normal external request to add aircraft
|
||||
AddByTimer, //!< add pending aircraft by timer
|
||||
AddAfterAdded, //!< add pending because object successfully added
|
||||
AddedAfterRemoved //!< added again after removed
|
||||
};
|
||||
|
||||
//! Mode as string
|
||||
const QString &modeToString(AircraftAddMode mode);
|
||||
|
||||
//! Dispatch SimConnect messages
|
||||
void dispatch();
|
||||
|
||||
//! Implementation of add remote aircraft, which also handles FSX specific adding one by one
|
||||
//! \remark main purpose of this function is to only add one aircraft at a time,
|
||||
//! and only if simulator is not paused/stopped
|
||||
bool physicallyAddRemoteAircraftImpl(const BlackMisc::Simulation::CSimulatedAircraft &newRemoteAircraft, AircraftAddMode addMode);
|
||||
|
||||
//! Remove aircraft no longer in provider
|
||||
//! \remark kind of cleanup function, in an ideal this should never need to cleanup something
|
||||
BlackMisc::Aviation::CCallsignSet physicallyRemoveAircraftNotInProvider();
|
||||
|
||||
//! Handle that an object has been added in simulator
|
||||
//! \remark checks if the object was really added after an add request and not directly removed again
|
||||
bool deferredSimulatorReportedObjectAdded(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
//! Verify that an object has been added in simulator
|
||||
//! \remark checks if the object was really added after an "add request" and not directly removed again
|
||||
void verifyAddedRemoteAircraft(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraftIn);
|
||||
|
||||
//! Add next aircraft based on timer
|
||||
void addPendingAircraftByTimer();
|
||||
|
||||
//! Add next aircraft after another has been confirmed
|
||||
void addPendingAircraftAfterAdded();
|
||||
|
||||
//! Try to add the next aircraft (one by one)
|
||||
void addPendingAircraft();
|
||||
void addPendingAircraft(AircraftAddMode mode);
|
||||
|
||||
//! Remove as m_addPendingAircraft and m_aircraftToAddAgainWhenRemoved
|
||||
void removeAsPendingAndAddAgain(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Call this method to declare the simulator connected
|
||||
void setSimConnected();
|
||||
@@ -163,6 +189,9 @@ namespace BlackSimPlugin
|
||||
//! Called when simulator has started
|
||||
void onSimRunning();
|
||||
|
||||
//! Deferred version of onSimRunning to avoid jitter
|
||||
void onSimRunningDefered(qint64 referenceTs);
|
||||
|
||||
//! Slot called every visual frame
|
||||
void onSimFrame();
|
||||
|
||||
@@ -200,6 +229,7 @@ namespace BlackSimPlugin
|
||||
|
||||
//! Send lights to simulator (those which have to be toggled)
|
||||
//! \remark challenge here is that I can only sent those value if I have already obtained the current light state from simulator
|
||||
//! \param force send lights even if they appear to be the same
|
||||
void sendToggledLightsToSimulator(const CSimConnectObject &simObj, const BlackMisc::Aviation::CAircraftLights &lightsWanted, bool force = false);
|
||||
|
||||
//! Called when data about our own aircraft are received
|
||||
@@ -265,12 +295,15 @@ namespace BlackSimPlugin
|
||||
static constexpr int RequestSimDataOffset = 0 * MaxSimObjects;
|
||||
static constexpr int RequestLightsOffset = 1 * MaxSimObjects;
|
||||
static constexpr int AddPendingAircraftIntervalMs = 20 * 1000;
|
||||
static constexpr int DispatchIntervalMs = 10;
|
||||
static constexpr int DispatchIntervalMs = 10; //!< how often with run the FSX event queue
|
||||
static constexpr int DeferSimulatingFlagMs = 1500; //! simulating can jitter at startup (simulating->stopped->simulating, multiple start events), so we defer detection
|
||||
static constexpr int DeferResendingLights = 2500; //! Resend light state when aircraft light state was not yet available
|
||||
|
||||
QString m_simConnectVersion; //!< SimConnect version
|
||||
bool m_simConnected = false; //!< Is simulator connected?
|
||||
bool m_simSimulating = false; //!< Simulator running?
|
||||
bool m_useSbOffsets = true; //!< with SB offsets
|
||||
qint64 m_simulatingChangedTs = -1; //!< timestamp, when simulating changed (used to avoid jitter)
|
||||
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
|
||||
|
||||
@@ -156,21 +156,13 @@ namespace BlackSimPlugin
|
||||
bool success = simulatorFsx->setSimConnectObjectId(requestId, objectId);
|
||||
if (!success) { break; } // not an request ID of ours
|
||||
|
||||
success = simulatorFsx->simulatorReportedObjectAdded(objectId);
|
||||
if (success)
|
||||
{
|
||||
const CSimConnectObject simObject = simulatorFsx->getSimConnectObjects().getSimObjectForObjectId(objectId);
|
||||
HRESULT result = S_OK;
|
||||
result += simulatorFsx->requestDataForSimObject(simObject);
|
||||
result += simulatorFsx->requestLightsForSimObject(simObject);
|
||||
Q_UNUSED(result);
|
||||
}
|
||||
else
|
||||
success = simulatorFsx->simulatorReportedObjectAdded(objectId); // trigger follow up actions
|
||||
if (!success)
|
||||
{
|
||||
const CSimulatedAircraft remoteAircraft(simulatorFsx->getSimConnectObjects().getSimObjectForObjectId(objectId).getAircraft());
|
||||
const CStatusMessage msgAdd = CStatusMessage(simulatorFsx).error("Cannot add object %1") << objectId;
|
||||
CLogMessage::preformatted(msgAdd);
|
||||
emit simulatorFsx->physicallyAddingRemoteModelFailed(remoteAircraft, msgAdd);
|
||||
const CStatusMessage msg = CStatusMessage(simulatorFsx).error("Cannot add object %1, cs: '%2' model: '%3'") << objectId << remoteAircraft.getCallsignAsString() << remoteAircraft.getModelString();
|
||||
CLogMessage::preformatted(msg);
|
||||
emit simulatorFsx->physicallyAddingRemoteModelFailed(remoteAircraft, msg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user