refs #533, fixes "CContextSimulator::ps_addRemoteAircraft is never called"

* reordered use of fireDelayedReadyForModelMatching
* better calls / params depending on received packet(FSInn / Icao code)
* fixed search in DB data
* works now with and without DB data present
This commit is contained in:
Klaus Basan
2015-12-02 00:50:00 +01:00
parent 39796f2f06
commit a863f99c9d
6 changed files with 178 additions and 104 deletions

View File

@@ -166,10 +166,8 @@ namespace BlackCore
Q_ASSERT_X(c2, Q_FUNC_INFO, "connect failed");
QMetaObject::Connection c3 = connect(this, &CAirspaceMonitor::removedAircraft, receiver, removedAircraftSlot);
Q_ASSERT_X(c3, Q_FUNC_INFO, "connect failed");
//! \todo remove old workaround if new version with receiver works
// trick is to use the Queued signal here
// analyzer (own thread) -> airspaceAircraftSnapshot -> AirspaceMonitor -> airspaceAircraftSnapshot queued in main thread
// QMetaObject::Connection c4 = this->connect(this, &CAirspaceMonitor::airspaceAircraftSnapshot, receiver, aircraftSnapshotSlot);
QMetaObject::Connection c4 = this->connect(this->m_analyzer, &CAirspaceAnalyzer::airspaceAircraftSnapshot, receiver, aircraftSnapshotSlot, Qt::QueuedConnection);
Q_ASSERT_X(c4, Q_FUNC_INFO, "connect failed");
return QList<QMetaObject::Connection>({ c1, c2, c3, c4});
@@ -252,7 +250,7 @@ namespace BlackCore
CUserList CAirspaceMonitor::getUsers() const
{
CUserList users;
foreach(CAtcStation station, this->m_atcStationsOnline)
foreach (CAtcStation station, this->m_atcStationsOnline)
{
CUser user = station.getController();
users.push_back(user);
@@ -482,30 +480,6 @@ namespace BlackCore
if (flags & INetwork::SupportsAircraftConfigs) m_network->sendAircraftConfigQuery(callsign);
}
void CAirspaceMonitor::ps_customFSinnPacketReceived(const CCallsign &callsign, const QString &airlineIcaoDesignator, const QString &aircraftIcaoDesignator, const QString &combinedAircraftType, const QString &model)
{
if (!this->m_connected || callsign.isEmpty() || model.isEmpty()) { return; }
// Request of other client, I can get the other's model from that
Q_UNUSED(combinedAircraftType);
CPropertyIndexVariantMap vm({ CClient::IndexModel, CAircraftModel::IndexModelString }, model);
vm.addValue({ CClient::IndexModel, CAircraftModel::IndexModelType }, static_cast<int>(CAircraftModel::TypeQueriedFromNetwork));
if (!this->m_otherClients.containsCallsign(callsign))
{
// with custom packets it can happen,
// the packet is received before any other packet
this->m_otherClients.push_back(CClient(callsign));
}
this->m_otherClients.applyIf(&CClient::getCallsign, callsign, vm);
// ICAO response from custom data
if (!aircraftIcaoDesignator.isEmpty())
{
// hand over, same functionality as would be needed here
this->ps_icaoCodesReceived(callsign, aircraftIcaoDesignator, airlineIcaoDesignator, "");
}
}
void CAirspaceMonitor::ps_serverReplyReceived(const CCallsign &callsign, const QString &server)
{
if (!this->m_connected || callsign.isEmpty() || server.isEmpty()) { return; }
@@ -563,6 +537,7 @@ namespace BlackCore
void CAirspaceMonitor::fireDelayedReadyForModelMatching(const CCallsign &callsign, int trial, int delayMs)
{
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign");
BlackMisc::singleShot(delayMs, QThread::currentThread(), [ = ]()
{
this->ps_sendReadyForModelMatching(callsign, trial + 1);
@@ -603,22 +578,23 @@ namespace BlackCore
void CAirspaceMonitor::ps_sendReadyForModelMatching(const CCallsign &callsign, int trial)
{
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign");
// some checks for special conditions, e.g. logout -> empty list, but still signals pending
CSimulatedAircraft remoteAircraft;
{
QReadLocker l(&m_lockAircraft);
if (!this->m_connected || this->m_aircraftInRange.isEmpty()) { return; }
if (!this->m_aircraftInRange.containsCallsign(callsign)) { return; }
if (!this->m_connected) { return; }
// build simulated aircraft and crosscheck if all data are available
remoteAircraft = CSimulatedAircraft(this->m_aircraftInRange.findFirstByCallsign(callsign));
Q_ASSERT_X(remoteAircraft.hasValidCallsign(), Q_FUNC_INFO, "Invalid callsign");
}
// check if the name and ICAO query went properly through
bool dataComplete =
remoteAircraft.hasAircraftDesignator() &&
(!m_serverSupportsNameQuery || remoteAircraft.getModel().hasModelString());
// check if the name and ICAO query went properly through,
// those usually means the aircraft are in range and can be used
bool inRange = remoteAircraft.hasValidCallsign();
bool dataComplete = inRange && remoteAircraft.hasAircraftDesignator() &&
(!m_serverSupportsNameQuery || remoteAircraft.getModel().hasModelString());
if (trial < 3 && !dataComplete)
{
@@ -627,8 +603,21 @@ namespace BlackCore
return;
}
Q_ASSERT(remoteAircraft.hasAircraftDesignator());
Q_ASSERT(!m_serverSupportsNameQuery || remoteAircraft.hasValidRealName());
if (!inRange)
{
// here we assume user has logged out, incomplete data because of traffic sim, etc.
CLogMessage(this).debug() << "Aircraft not in range anymore " << callsign.toQString();
return;
}
if (!dataComplete)
{
// even after all the trials, still no designator
// something is wrong here
CLogMessage(this).warning("Cannot retrieve model information for %1") << callsign.toQString();
return; // maybe we like to continue here, hard so say
}
Q_ASSERT_X(!m_serverSupportsNameQuery || remoteAircraft.hasValidRealName(), Q_FUNC_INFO, "invalid model data");
emit this->readyForModelMatching(remoteAircraft);
}
@@ -764,12 +753,40 @@ namespace BlackCore
}
}
void CAirspaceMonitor::ps_customFSinnPacketReceived(const CCallsign &callsign, const QString &airlineIcaoDesignator, const QString &aircraftIcaoDesignator, const QString &combinedAircraftType, const QString &model)
{
if (!this->m_connected || callsign.isEmpty() || model.isEmpty()) { return; }
// Request of other client, I can get the other's model from that
Q_UNUSED(combinedAircraftType);
CPropertyIndexVariantMap vm({ CClient::IndexModel, CAircraftModel::IndexModelString }, model);
vm.addValue({ CClient::IndexModel, CAircraftModel::IndexModelType }, static_cast<int>(CAircraftModel::TypeQueriedFromNetwork));
if (!this->m_otherClients.containsCallsign(callsign))
{
// with custom packets it can happen that
// the packet is received before any other packet
this->m_otherClients.push_back(CClient(callsign));
}
this->m_otherClients.applyIf(&CClient::getCallsign, callsign, vm); // update client info
// ICAO response from custom data
if (!aircraftIcaoDesignator.isEmpty())
{
// hand over, same functionality as would be needed here
this->icaoOrFsdDataReceived(callsign, aircraftIcaoDesignator, airlineIcaoDesignator, "", model, CAircraftModel::TypeFsdData);
}
}
void CAirspaceMonitor::ps_icaoCodesReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &aircraftIcaoDesignator, const QString &airlineIcaoDesignator, const QString &livery)
{
this->icaoOrFsdDataReceived(callsign, aircraftIcaoDesignator, airlineIcaoDesignator, livery, "", CAircraftModel::TypeQueriedFromNetwork);
}
void CAirspaceMonitor::icaoOrFsdDataReceived(const CCallsign &callsign, const QString &aircraftIcaoDesignator, const QString &airlineIcaoDesignator, const QString &livery, const QString &modelString, CAircraftModel::ModelType type)
{
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "not in main thread");
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "no callsign");
if (!this->m_connected) { return; }
if (aircraftIcaoDesignator.isEmpty() && airlineIcaoDesignator.isEmpty() && livery.isEmpty()) { return; }
CSimulatedAircraft remoteAircraft(this->getAircraftInRangeForCallsign(callsign));
@@ -779,69 +796,97 @@ namespace BlackCore
if (existingAircraft)
{
model = remoteAircraft.getModel();
m_modelCache.remove(callsign);
m_modelCache.remove(callsign); // normally already removed
}
else if (m_modelCache.contains(callsign))
{
model = m_modelCache[callsign];
model = m_modelCache[callsign];
}
// already matched with DB?
if (model.getModelType() != CAircraftModel::TypeQueriedFromNetwork && model.getModelType() != CAircraftModel::TypeFsdData) { return; }
if (!model.canInitializeFromFsd()) { return; }
// update model string if not yet existing
if (!model.hasModelString() && !modelString.isEmpty()) { model.setModelString(modelString); }
if (model.getModelType() == CAircraftModel::TypeUnknown || model.getModelType() == CAircraftModel::TypeQueriedFromNetwork)
{
model.setModelType(type); // update type if no type yet
}
// we have no DB model yet, but do we have model string?
if (model.hasModelString())
{
// if we find the model here we have a fully defined DB model
CAircraftModel modelFromDb(this->getModelForModelString(model.getModelString()));
if (modelFromDb.hasValidDbKey()) { model = modelFromDb; }
}
// only if not yet matched with DB
if (!model.hasValidDbKey() && CLivery::isValidCombinedCode(livery))
if (!model.hasValidDbKey())
{
CAircraftModelList models(this->getModelsForAircraftDesignatorAndLiveryCombinedCode(aircraftIcaoDesignator, livery));
if (models.isEmpty())
// try to match by livery
if (CLivery::isValidCombinedCode(livery))
{
// no models for that livery
CLivery databaseLivery(this->getLiveryForCombinedCode(livery));
if (databaseLivery.hasValidDbKey())
// search DB model by livery
CAircraftModelList models(this->getModelsForAircraftDesignatorAndLiveryCombinedCode(aircraftIcaoDesignator, livery));
if (models.isEmpty())
{
// we have found a livery in the DB
model.setLivery(databaseLivery);
// no models for that livery, search for livery only
CLivery databaseLivery(this->getLiveryForCombinedCode(livery));
if (databaseLivery.hasValidDbKey())
{
// we have found a livery in the DB
model.setLivery(databaseLivery);
}
}
else
{
// create a pseudo livery, try to find airline first
CAirlineIcaoCode airlineIcao(this->getAirlineIcaoCodeForDesignator(airlineIcaoDesignator));
if (!airlineIcao.hasValidDbKey()) { airlineIcao = CAirlineIcaoCode(airlineIcaoDesignator); }
CLivery liveryDummy(livery, airlineIcao, "Generated");
model.setLivery(liveryDummy);
// model by livery data found
model = models.front();
}
}
// if no DB livery, create own dummy livery
if (!model.hasValidDbKey() && !model.getLivery().hasValidDbKey())
{
// create a pseudo livery, try to find airline first
CAirlineIcaoCode airlineIcao(this->getAirlineIcaoCodeForDesignator(airlineIcaoDesignator));
if (!airlineIcao.hasValidDbKey())
{
// no DB data, we update as much as possible
airlineIcao = model.getAirlineIcaoCode();
airlineIcao.updateMissingParts(CAirlineIcaoCode(airlineIcaoDesignator));
}
CLivery liveryDummy(livery, airlineIcao, "Generated");
model.setLivery(liveryDummy);
}
if (!model.getAircraftIcaoCode().hasValidDbKey())
{
CAircraftIcaoCode aircraftIcao(this->getAircraftIcaoCodeForDesignator(aircraftIcaoDesignator));
if (!aircraftIcao.hasValidDbKey()) { aircraftIcao = CAircraftIcaoCode(aircraftIcaoDesignator); }
model.setModelType(CAircraftModel::TypeFsdData);
if (!aircraftIcao.hasValidDbKey())
{
// no DB data, we update as much as possible
aircraftIcao = model.getAircraftIcaoCode();
aircraftIcao.updateMissingParts(CAircraftIcaoCode(aircraftIcaoDesignator));
}
model.setAircraftIcaoCode(aircraftIcao);
}
} // model from DB
{
QWriteLocker l(&m_lockAircraft);
if (this->m_aircraftInRange.containsCallsign(callsign))
{
// we know the aircraft, so we update it
this->m_aircraftInRange.setAircraftModel(callsign, model);
}
else
{
// model by livery data
model = models.front();
}
}
int c = 0;
{
QWriteLocker l(&m_lockAircraft);
if (!this->m_aircraftInRange.containsCallsign(callsign))
{
// keep in cache, as aircraft is not already known
this->m_modelCache.insert(callsign, model);
return;
}
// we know the aircraft, so we update
c = this->m_aircraftInRange.setAircraftModel(callsign, model);
}
if (c > 0) { ps_sendReadyForModelMatching(callsign, 1); }
} // lock
}
void CAirspaceMonitor::ps_aircraftUpdateReceived(const CAircraftSituation &situation, const CTransponder &transponder)
@@ -856,9 +901,8 @@ namespace BlackCore
this->storeAircraftSituation(situation);
emit this->addedAircraftSituation(situation);
QWriteLocker l(&m_lockAircraft);
bool exists = this->m_aircraftInRange.containsCallsign(callsign);
if (!exists)
bool existsInRange = this->m_aircraftInRange.containsCallsign(callsign);
if (!existsInRange)
{
// new aircraft
CSimulatedAircraft aircraft;
@@ -869,23 +913,27 @@ namespace BlackCore
this->updateWithVatsimDataFileData(aircraft);
// ICAO from cache if avialable
bool setModel = false;
if (this->m_modelCache.contains(callsign))
bool setModelFromCache = false;
{
CAircraftModel model = this->m_modelCache.value(callsign);
this->m_modelCache.remove(callsign);
aircraft.setModel(model);
setModel = true;
}
CAircraftModel model;
QWriteLocker l(&m_lockAircraft);
if (this->m_modelCache.contains(callsign))
{
model = this->m_modelCache.value(callsign);
this->m_modelCache.remove(callsign);
aircraft.setModel(model);
setModelFromCache = true;
}
// only place where aircraft is added
this->m_aircraftInRange.push_back(aircraft);
// only place where aircraft is added
this->m_aircraftInRange.push_back(aircraft);
// new client, there is a chance it has been already created by custom packet
if (!this->m_otherClients.containsCallsign(callsign))
{
CClient c(callsign);
this->m_otherClients.push_back(c); // initial, will be filled by data later
// new client, there is a chance it has been already created by custom packet
if (!this->m_otherClients.containsCallsign(callsign))
{
CClient c(callsign);
this->m_otherClients.push_back(c); // initial, will be filled by data later
}
}
// only if still connected
@@ -894,7 +942,11 @@ namespace BlackCore
// the order here makes some sense, as we hope to receive ICAO codes last, and everthing else already in place
// Send a custom FSinn query only if we don't have the exact model yet
CClient c = this->m_otherClients.findByCallsign(callsign).frontOrDefault();
CClient c;
{
QReadLocker l(&m_lockAircraft);
c = this->m_otherClients.findByCallsign(callsign).frontOrDefault();
}
CAircraftModel::ModelType modelType = c.getAircraftModel().getModelType();
if (modelType != CAircraftModel::TypeQueriedFromNetwork && modelType != CAircraftModel::TypeDatabaseEntry)
{
@@ -905,14 +957,19 @@ namespace BlackCore
this->m_network->sendCapabilitiesQuery(callsign);
this->m_network->sendServerQuery(callsign);
// keep as last
if (setModel)
// do this as last thing
if (setModelFromCache)
{
this->fireDelayedReadyForModelMatching(callsign);
// we have had at least some information,
// means either ICAO codes or FSInn package has already been received
this->ps_sendReadyForModelMatching(callsign, 1);
}
else
{
// no info yet, query ICAO codes at least
// allow some time for the data to arrive before ready for model matching
this->m_network->sendIcaoCodesQuery(callsign);
this->fireDelayedReadyForModelMatching(callsign);
}
emit this->addedAircraft(aircraft);
} // connected
@@ -928,7 +985,10 @@ namespace BlackCore
vm.addValue(CSimulatedAircraft::IndexDistanceToOwnAircraft, distance);
// here I expect always a changed value
this->m_aircraftInRange.applyIfCallsign(callsign, vm);
{
QWriteLocker l(&m_lockAircraft);
this->m_aircraftInRange.applyIfCallsign(callsign, vm);
}
}
emit this->changedAircraftInRange();
@@ -946,25 +1006,25 @@ namespace BlackCore
// Interim packets do not have groundspeed, hence set the last known value.
// If there is no full position available yet, throw this interim position away.
CAircraftSituation iterimSituation(situation);
CAircraftSituation interimSituation(situation);
{
QReadLocker l(&m_lockSituations);
auto history = this->m_situationsByCallsign[callsign];
if (history.empty()) { return; } // we need one full situation
iterimSituation.setCurrentUtcTime();
iterimSituation.setGroundspeed(history.latestValue().getGroundSpeed());
interimSituation.setCurrentUtcTime();
interimSituation.setGroundspeed(history.latestValue().getGroundSpeed());
}
// store situation history
this->storeAircraftSituation(iterimSituation);
emit this->addedAircraftSituation(iterimSituation);
this->storeAircraftSituation(interimSituation);
emit this->addedAircraftSituation(interimSituation);
// update aircraft
//! \todo skip aircraft updates for interim positions as for performance reasons
CLength distance = getOwnAircraft().calculateGreatCircleDistance(iterimSituation.getPosition());
CLength distance = getOwnAircraft().calculateGreatCircleDistance(interimSituation.getPosition());
distance.switchUnit(CLengthUnit::NM()); // lloks nicer
CPropertyIndexVariantMap vm;
vm.addValue(CSimulatedAircraft::IndexSituation, iterimSituation);
vm.addValue(CSimulatedAircraft::IndexSituation, interimSituation);
vm.addValue(CSimulatedAircraft::IndexDistanceToOwnAircraft, distance);
// here I expect always a changed value