mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-20 04:25:42 +08:00
Ref T289, merge CSimulatorCommonn/ISimulator
This commit is contained in:
@@ -7,14 +7,25 @@
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "blackcore/db/databaseutils.h"
|
||||
#include "blackcore/simulator.h"
|
||||
#include "blackcore/webdataservices.h"
|
||||
#include "blackcore/application.h"
|
||||
#include "blackmisc/directoryutils.h"
|
||||
#include "blackmisc/logmessage.h"
|
||||
|
||||
#include <QFlag>
|
||||
#include <Qt>
|
||||
#include <QtGlobal>
|
||||
#include <QPointer>
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QThread>
|
||||
#include <QDir>
|
||||
#include <QUrl>
|
||||
#include <QDesktopServices>
|
||||
#include <functional>
|
||||
|
||||
using namespace BlackConfig;
|
||||
using namespace BlackMisc;
|
||||
@@ -24,9 +35,21 @@ using namespace BlackMisc::Simulation;
|
||||
using namespace BlackMisc::PhysicalQuantities;
|
||||
using namespace BlackMisc::Network;
|
||||
using namespace BlackMisc::Weather;
|
||||
using namespace BlackCore::Db;
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
const CLogCategoryList &ISimulator::getLogCategories()
|
||||
{
|
||||
static const CLogCategoryList cats({ CLogCategory::driver(), CLogCategory::plugin() });
|
||||
return cats;
|
||||
}
|
||||
|
||||
ISimulator::~ISimulator()
|
||||
{
|
||||
this->safeKillTimer();
|
||||
}
|
||||
|
||||
ISimulator::SimulatorStatus ISimulator::getSimulatorStatus() const
|
||||
{
|
||||
if (!this->isConnected()) { return ISimulator::Disconnected; }
|
||||
@@ -37,6 +60,208 @@ namespace BlackCore
|
||||
return status;
|
||||
}
|
||||
|
||||
bool ISimulator::logicallyRemoveRemoteAircraft(const CCallsign &callsign)
|
||||
{
|
||||
// if not restriced, directly change
|
||||
if (!this->getInterpolationSetupGlobal().isRenderingRestricted())
|
||||
{
|
||||
m_statsPhysicallyAddedAircraft++;
|
||||
this->callPhysicallyRemoveRemoteAircraft(callsign);
|
||||
return true;
|
||||
}
|
||||
|
||||
// will be added with next snapshot onRecalculatedRenderedAircraft
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ISimulator::logicallyAddRemoteAircraft(const CSimulatedAircraft &remoteAircraft)
|
||||
{
|
||||
Q_ASSERT_X(remoteAircraft.hasModelString(), Q_FUNC_INFO, "Missing model string");
|
||||
Q_ASSERT_X(remoteAircraft.hasCallsign(), Q_FUNC_INFO, "Missing callsign");
|
||||
|
||||
const bool renderingRestricted = this->getInterpolationSetupGlobal().isRenderingRestricted();
|
||||
if (this->showDebugLogMessage()) { this->debugLogMessage(Q_FUNC_INFO, QString("Restricted: %1 cs: '%2' enabled: %3").arg(boolToYesNo(renderingRestricted), remoteAircraft.getCallsignAsString(), boolToYesNo(remoteAircraft.isEnabled()))); }
|
||||
if (!remoteAircraft.isEnabled()) { return false; }
|
||||
|
||||
// if not restriced, directly change
|
||||
if (!renderingRestricted) { this->callPhysicallyAddRemoteAircraft(remoteAircraft); return true; }
|
||||
|
||||
// restricted -> will be added with next snapshot onRecalculatedRenderedAircraft
|
||||
return false;
|
||||
}
|
||||
|
||||
void ISimulator::highlightAircraft(const CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const CTime &displayTime)
|
||||
{
|
||||
const CCallsign cs(aircraftToHighlight.getCallsign());
|
||||
m_highlightedAircraft.removeByCallsign(cs);
|
||||
if (enableHighlight)
|
||||
{
|
||||
const qint64 deltaT = displayTime.valueRounded(CTimeUnit::ms(), 0);
|
||||
m_highlightEndTimeMsEpoch = QDateTime::currentMSecsSinceEpoch() + deltaT;
|
||||
m_highlightedAircraft.push_back(aircraftToHighlight);
|
||||
}
|
||||
}
|
||||
|
||||
bool ISimulator::followAircraft(const CCallsign &callsign)
|
||||
{
|
||||
Q_UNUSED(callsign);
|
||||
return false;
|
||||
}
|
||||
|
||||
void ISimulator::setWeatherActivated(bool activated)
|
||||
{
|
||||
m_isWeatherActivated = activated;
|
||||
if (m_isWeatherActivated)
|
||||
{
|
||||
const auto selectedWeatherScenario = m_weatherScenarioSettings.get();
|
||||
if (!CWeatherScenario::isRealWeatherScenario(selectedWeatherScenario))
|
||||
{
|
||||
m_lastWeatherPosition = {};
|
||||
this->injectWeatherGrid(CWeatherGrid::getByScenario(selectedWeatherScenario));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ISimulator::reloadWeatherSettings()
|
||||
{
|
||||
if (!m_isWeatherActivated) { return; }
|
||||
const auto selectedWeatherScenario = m_weatherScenarioSettings.get();
|
||||
if (!CWeatherScenario::isRealWeatherScenario(selectedWeatherScenario))
|
||||
{
|
||||
m_lastWeatherPosition = {};
|
||||
this->injectWeatherGrid(CWeatherGrid::getByScenario(selectedWeatherScenario));
|
||||
}
|
||||
}
|
||||
|
||||
void ISimulator::clearAllRemoteAircraftData()
|
||||
{
|
||||
// rendering related stuff
|
||||
m_addAgainAircraftWhenRemoved.clear();
|
||||
m_callsignsToBeRendered.clear();
|
||||
m_clampedLogMsg.clear();
|
||||
m_lastSentParts.clear();
|
||||
m_lastSentSituations.clear();
|
||||
m_updateRemoteAircraftInProgress = false;
|
||||
|
||||
this->clearInterpolationSetupsPerCallsign();
|
||||
this->resetHighlighting();
|
||||
this->resetAircraftStatistics();
|
||||
}
|
||||
|
||||
void ISimulator::debugLogMessage(const QString &msg)
|
||||
{
|
||||
if (!this->showDebugLogMessage()) { return; }
|
||||
if (msg.isEmpty()) { return; }
|
||||
const CStatusMessage m = CStatusMessage(this).info("%1") << msg;
|
||||
emit this->driverMessages(m);
|
||||
}
|
||||
|
||||
void ISimulator::debugLogMessage(const QString &funcInfo, const QString &msg)
|
||||
{
|
||||
if (!this->showDebugLogMessage()) { return; }
|
||||
if (msg.isEmpty()) { return; }
|
||||
const CStatusMessage m = CStatusMessage(this).info("%1 %2") << msg << funcInfo;
|
||||
emit this->driverMessages(m);
|
||||
}
|
||||
|
||||
bool ISimulator::showDebugLogMessage() const
|
||||
{
|
||||
const bool show = this->getInterpolationSetupGlobal().showSimulatorDebugMessages();
|
||||
return show;
|
||||
}
|
||||
|
||||
void ISimulator::resetAircraftFromProvider(const CCallsign &callsign)
|
||||
{
|
||||
const CSimulatedAircraft aircraft(this->getAircraftInRangeForCallsign(callsign));
|
||||
const bool enabled = aircraft.isEnabled();
|
||||
if (enabled)
|
||||
{
|
||||
// are we already visible?
|
||||
if (!this->isPhysicallyRenderedAircraft(callsign))
|
||||
{
|
||||
this->callPhysicallyAddRemoteAircraft(aircraft); // enable/disable
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->callPhysicallyRemoveRemoteAircraft(callsign);
|
||||
}
|
||||
}
|
||||
|
||||
void ISimulator::clearData(const CCallsign &callsign)
|
||||
{
|
||||
m_highlightedAircraft.removeByCallsign(callsign);
|
||||
m_statsPhysicallyRemovedAircraft++;
|
||||
m_clampedLogMsg.clear();
|
||||
m_lastSentParts.remove(callsign);
|
||||
m_lastSentSituations.remove(callsign);
|
||||
m_clampedLogMsg.remove(callsign);
|
||||
this->removeInterpolationSetupPerCallsign(callsign);
|
||||
}
|
||||
|
||||
void ISimulator::reset()
|
||||
{
|
||||
this->clearAllRemoteAircraftData();
|
||||
}
|
||||
|
||||
void ISimulator::resetHighlighting()
|
||||
{
|
||||
m_highlightedAircraft.clear();
|
||||
m_blinkCycle = false;
|
||||
m_highlightEndTimeMsEpoch = false;
|
||||
}
|
||||
|
||||
void ISimulator::stopHighlighting()
|
||||
{
|
||||
// restore
|
||||
const CSimulatedAircraftList highlightedAircraft(m_highlightedAircraft);
|
||||
for (const CSimulatedAircraft &aircraft : highlightedAircraft)
|
||||
{
|
||||
// get the current state for this aircraft
|
||||
// it might has been removed in the meantime
|
||||
const CCallsign cs(aircraft.getCallsign());
|
||||
this->resetAircraftFromProvider(cs);
|
||||
}
|
||||
this->resetHighlighting();
|
||||
}
|
||||
|
||||
void ISimulator::oneSecondTimerTimeout()
|
||||
{
|
||||
this->blinkHighlightedAircraft();
|
||||
}
|
||||
|
||||
void ISimulator::safeKillTimer()
|
||||
{
|
||||
if (m_timerId < 0) { return; }
|
||||
this->killTimer(m_timerId);
|
||||
m_timerId = -1;
|
||||
}
|
||||
|
||||
void ISimulator::injectWeatherGrid(const CWeatherGrid &weatherGrid)
|
||||
{
|
||||
Q_UNUSED(weatherGrid);
|
||||
}
|
||||
|
||||
void ISimulator::blinkHighlightedAircraft()
|
||||
{
|
||||
if (m_highlightedAircraft.isEmpty() || m_highlightEndTimeMsEpoch < 1) { return; }
|
||||
if (this->isShuttingDown()) { return; }
|
||||
m_blinkCycle = !m_blinkCycle;
|
||||
|
||||
if (QDateTime::currentMSecsSinceEpoch() > m_highlightEndTimeMsEpoch)
|
||||
{
|
||||
this->stopHighlighting();
|
||||
return;
|
||||
}
|
||||
|
||||
// blink mode, toggle aircraft
|
||||
for (const CSimulatedAircraft &aircraft : as_const(m_highlightedAircraft))
|
||||
{
|
||||
if (m_blinkCycle) { this->callPhysicallyRemoveRemoteAircraft(aircraft.getCallsign(), true); }
|
||||
else { this->callPhysicallyAddRemoteAircraft(aircraft); }
|
||||
}
|
||||
}
|
||||
|
||||
CInterpolationAndRenderingSetupPerCallsign ISimulator::getInterpolationSetupConsolidated(const CCallsign &callsign) const
|
||||
{
|
||||
CInterpolationAndRenderingSetupPerCallsign setup = this->getInterpolationSetupPerCallsignOrDefault(callsign);
|
||||
@@ -62,11 +287,205 @@ namespace BlackCore
|
||||
emit this->receivedRequestedElevation(plane, callsign);
|
||||
}
|
||||
|
||||
void ISimulator::resetAircraftStatistics()
|
||||
{
|
||||
m_statsUpdateAircraftRuns = 0;
|
||||
m_statsUpdateAircraftTimeAvgMs = 0;
|
||||
m_statsUpdateAircraftTimeTotalMs = 0;
|
||||
m_statsMaxUpdateTimeMs = 0;
|
||||
m_statsCurrentUpdateTimeMs = 0;
|
||||
m_statsPhysicallyAddedAircraft = 0;
|
||||
m_statsPhysicallyRemovedAircraft = 0;
|
||||
m_statsLastUpdateAircraftRequestedMs = 0;
|
||||
m_statsUpdateAircraftRequestedDeltaMs = 0;
|
||||
m_statsUpdateAircraftLimited = 0;
|
||||
ISimulationEnvironmentProvider::resetSimulationEnvironmentStatistics();
|
||||
}
|
||||
|
||||
bool ISimulator::parseCommandLine(const QString &commandLine, const CIdentifier &originator)
|
||||
{
|
||||
if (this->isMyIdentifier(originator)) { return false; }
|
||||
if (this->isShuttingDown()) { return false; }
|
||||
|
||||
if (commandLine.isEmpty()) { return false; }
|
||||
CSimpleCommandParser parser({ ".plugin", ".drv", ".driver" });
|
||||
parser.parse(commandLine);
|
||||
if (!parser.isKnownCommand()) { return false; }
|
||||
|
||||
// .plugin unload
|
||||
if (parser.matchesPart(1, "unload")) { this->unload(); return true; }
|
||||
|
||||
// .plugin log interpolator
|
||||
const QString part1(parser.part(1).toLower().trimmed());
|
||||
if (part1.startsWith("logint") && parser.hasPart(2))
|
||||
{
|
||||
const QString part2 = parser.part(2).toLower();
|
||||
if (part2 == "off" || part2 == "false")
|
||||
{
|
||||
CStatusMessage(this).info("Disabled interpolation logging");
|
||||
this->clearInterpolationLogCallsigns();
|
||||
return true;
|
||||
}
|
||||
if (part2 == "clear" || part2 == "clr")
|
||||
{
|
||||
m_interpolationLogger.clearLog();
|
||||
CStatusMessage(this).info("Cleared interpolation logging");
|
||||
this->clearInterpolationLogCallsigns();
|
||||
return true;
|
||||
}
|
||||
if (part2.startsWith("max"))
|
||||
{
|
||||
if (!parser.hasPart(3)) { return false; }
|
||||
bool ok;
|
||||
const int max = parser.part(3).toInt(&ok);
|
||||
if (!ok) { return false; }
|
||||
m_interpolationLogger.setMaxSituations(max);
|
||||
CStatusMessage(this).info("Max.situations logged: %1") << max;
|
||||
return true;
|
||||
}
|
||||
if (part2 == "write" || part2 == "save")
|
||||
{
|
||||
// stop logging of other log
|
||||
this->clearInterpolationLogCallsigns();
|
||||
|
||||
// write
|
||||
m_interpolationLogger.writeLogInBackground();
|
||||
CLogMessage(this).info("Started writing interpolation log");
|
||||
return true;
|
||||
}
|
||||
if (part2 == "show")
|
||||
{
|
||||
const QDir dir(CInterpolationLogger::getLogDirectory());
|
||||
if (CDirectoryUtils::isDirExisting(dir))
|
||||
{
|
||||
const QUrl dirUrl = QUrl::fromLocalFile(dir.absolutePath());
|
||||
QDesktopServices::openUrl(dirUrl); // show dir in browser
|
||||
}
|
||||
else
|
||||
{
|
||||
CLogMessage(this).warning("No interpolation log directory");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const CCallsign cs(part2.toUpper());
|
||||
if (!cs.isValid()) { return false; }
|
||||
if (this->getAircraftInRangeCallsigns().contains(cs))
|
||||
{
|
||||
CLogMessage(this).info("Will log interpolation for '%1'") << cs.asString();
|
||||
this->setLogCallsign(true, cs);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLogMessage(this).warning("Cannot log interpolation for '%1', no aircraft in range") << cs.asString();
|
||||
return false;
|
||||
}
|
||||
} // logint
|
||||
|
||||
if (part1.startsWith("spline") || part1.startsWith("linear"))
|
||||
{
|
||||
if (parser.hasPart(2))
|
||||
{
|
||||
const CCallsign cs(parser.part(2));
|
||||
const bool changed = this->setInterpolationMode(part1, cs);
|
||||
CLogMessage(this).info(changed ? "Changed interpolation mode for '%1'" : "Unchanged interpolation mode for '%1'") << cs.asString();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CInterpolationAndRenderingSetupGlobal setup = this->getInterpolationSetupGlobal();
|
||||
const bool changed = setup.setInterpolatorMode(part1);
|
||||
if (changed) { this->setInterpolationSetupGlobal(setup); }
|
||||
CLogMessage(this).info(changed ? "Changed interpolation mode globally" : "Unchanged interpolation mode");
|
||||
return true;
|
||||
}
|
||||
} // spline/linear
|
||||
|
||||
if (part1.startsWith("pos"))
|
||||
{
|
||||
CCallsign cs(parser.part(2).toUpper());
|
||||
if (!cs.isValid())
|
||||
{
|
||||
const CCallsignSet csSet = this->getLogCallsigns();
|
||||
if (csSet.size() != 1) { return false; }
|
||||
|
||||
// if there is just one we take that one
|
||||
cs = *csSet.begin();
|
||||
}
|
||||
|
||||
this->setLogCallsign(true, cs);
|
||||
CLogMessage(this).info("Display position for '%1'") << cs.asString();
|
||||
this->displayLoggedSituationInSimulator(cs, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parser.hasPart(2) && (part1.startsWith("aircraft") || part1.startsWith("ac")))
|
||||
{
|
||||
const QString part2 = parser.part(2).toLower();
|
||||
if (parser.hasPart(3) && (part2.startsWith("readd") || part2.startsWith("re-add")))
|
||||
{
|
||||
const QString cs = parser.part(3).toUpper();
|
||||
if (cs == "all")
|
||||
{
|
||||
this->physicallyRemoveAllRemoteAircraft();
|
||||
const CStatusMessageList msgs = this->debugVerifyStateAfterAllAircraftRemoved();
|
||||
this->clearAllRemoteAircraftData();
|
||||
if (!msgs.isEmpty()) { emit this->driverMessages(msgs); }
|
||||
const CSimulatedAircraftList aircraft = this->getAircraftInRange();
|
||||
for (const CSimulatedAircraft a : aircraft)
|
||||
{
|
||||
if (a.isEnabled()) { this->logicallyAddRemoteAircraft(a); }
|
||||
}
|
||||
}
|
||||
else if (CCallsign::isValidAircraftCallsign(cs))
|
||||
{
|
||||
this->logicallyReAddRemoteAircraft(cs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (parser.hasPart(3) && (part2.startsWith("rm") || part2.startsWith("remove")))
|
||||
{
|
||||
const QString cs = parser.part(3).toUpper();
|
||||
if (CCallsign::isValidAircraftCallsign(cs))
|
||||
{
|
||||
this->logicallyRemoveRemoteAircraft(cs);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (part1.startsWith("limit"))
|
||||
{
|
||||
const int perSecond = parser.toInt(2, -1);
|
||||
this->limitToUpdatesPerSecond(perSecond);
|
||||
CLogMessage(this).info("Remote aircraft updates limitations: %1") << this->updateAircraftLimitationInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
// driver specific cmd line arguments
|
||||
return this->parseDetails(parser);
|
||||
}
|
||||
|
||||
void ISimulator::registerHelp()
|
||||
{
|
||||
if (CSimpleCommandParser::registered("BlackCore::ISimulator")) { return; }
|
||||
CSimpleCommandParser::registerCommand({".drv", "alias: .driver .plugin"});
|
||||
CSimpleCommandParser::registerCommand({".drv unload", "unload driver"});
|
||||
CSimpleCommandParser::registerCommand({".drv limit number/secs.", "limit updates to number per second (0..off)"});
|
||||
CSimpleCommandParser::registerCommand({".drv logint callsign", "log interpolator for callsign"});
|
||||
CSimpleCommandParser::registerCommand({".drv logint off", "no log information for interpolator"});
|
||||
CSimpleCommandParser::registerCommand({".drv logint write", "write interpolator log to file"});
|
||||
CSimpleCommandParser::registerCommand({".drv logint clear", "clear current log"});
|
||||
CSimpleCommandParser::registerCommand({".drv logint max number", "max. number of entries logged"});
|
||||
CSimpleCommandParser::registerCommand({".drv pos callsign", "show position for callsign"});
|
||||
CSimpleCommandParser::registerCommand({".drv spline|linear callsign", "set spline/linear interpolator for one/all callsign(s)"});
|
||||
CSimpleCommandParser::registerCommand({".drv aircraft readd callsign", "add again (re-add) a given callsign"});
|
||||
CSimpleCommandParser::registerCommand({".drv aircraft readd all", "add again (re-add) all aircraft"});
|
||||
CSimpleCommandParser::registerCommand({".drv aircraft rm callsign", "remove a given callsign"});
|
||||
|
||||
if (CBuildConfig::isCompiledWithFsuipcSupport())
|
||||
{
|
||||
CSimpleCommandParser::registerCommand({".drv fsuipc on|off", "enable/disable FSUIPC (if applicable)"});
|
||||
@@ -84,6 +503,44 @@ namespace BlackCore
|
||||
return s.join(", ");
|
||||
}
|
||||
|
||||
bool ISimulator::isEqualLastSent(const CAircraftSituation &compare) const
|
||||
{
|
||||
Q_ASSERT_X(compare.hasCallsign(), Q_FUNC_INFO, "Need callsign");
|
||||
if (!m_lastSentSituations.contains(compare.getCallsign())) { return false; }
|
||||
if (compare.isNull()) { return false; }
|
||||
return compare.equalPbhVectorAltitude(m_lastSentSituations.value(compare.getCallsign()));
|
||||
}
|
||||
|
||||
bool ISimulator::isEqualLastSent(const CAircraftParts &compare, const CCallsign &callsign) const
|
||||
{
|
||||
if (callsign.isEmpty()) { return false; }
|
||||
if (!m_lastSentParts.contains(callsign)) { return false; }
|
||||
return compare.equalValues(m_lastSentParts.value(callsign));
|
||||
}
|
||||
|
||||
void ISimulator::rememberLastSent(const CAircraftSituation &sent)
|
||||
{
|
||||
Q_ASSERT_X(sent.hasCallsign(), Q_FUNC_INFO, "Need callsign");
|
||||
m_lastSentSituations.insert(sent.getCallsign(), sent);
|
||||
}
|
||||
|
||||
void ISimulator::rememberLastSent(const CAircraftParts &sent, const CCallsign &callsign)
|
||||
{
|
||||
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Need callsign");
|
||||
m_lastSentParts.insert(callsign, sent);
|
||||
}
|
||||
|
||||
CAircraftSituationList ISimulator::getLastSentCanLikelySkipNearGroundInterpolation() const
|
||||
{
|
||||
const QList<CAircraftSituation> situations = m_lastSentSituations.values();
|
||||
CAircraftSituationList skipped;
|
||||
for (const CAircraftSituation &s : situations)
|
||||
{
|
||||
if (s.canLikelySkipNearGroundInterpolation()) { skipped.push_back(s); }
|
||||
}
|
||||
return skipped;
|
||||
}
|
||||
|
||||
bool ISimulator::isAnyConnectedStatus(SimulatorStatus status)
|
||||
{
|
||||
return (status.testFlag(Connected) || status.testFlag(Simulating) || status.testFlag(Paused));
|
||||
@@ -104,7 +561,144 @@ namespace BlackCore
|
||||
IInterpolationSetupProvider(),
|
||||
CIdentifiable(this)
|
||||
{
|
||||
this->setObjectName("Simulator: " + pluginInfo.getIdentifier());
|
||||
ISimulator::registerHelp();
|
||||
|
||||
// provider signals, hook up with remote aircraft provider
|
||||
m_remoteAircraftProviderConnections.append(
|
||||
CRemoteAircraftAware::provider()->connectRemoteAircraftProviderSignals(
|
||||
this, // receiver must match object in bind
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::bind(&ISimulator::rapOnRemoteProviderRemovedAircraft, this, std::placeholders::_1),
|
||||
std::bind(&ISimulator::rapOnRecalculatedRenderedAircraft, this, std::placeholders::_1))
|
||||
);
|
||||
|
||||
// timer
|
||||
connect(&m_oneSecondTimer, &QTimer::timeout, this, &ISimulator::oneSecondTimerTimeout);
|
||||
m_oneSecondTimer.setObjectName(this->objectName().append(":m_oneSecondTimer"));
|
||||
m_oneSecondTimer.start(1000);
|
||||
|
||||
// swift data
|
||||
if (sApp && sApp->hasWebDataServices())
|
||||
{
|
||||
connect(sApp->getWebDataServices(), &CWebDataServices::swiftDbAllDataRead, this, &ISimulator::onSwiftDbAllDataRead, Qt::QueuedConnection);
|
||||
connect(sApp->getWebDataServices(), &CWebDataServices::swiftDbAirportsRead, this, &ISimulator::onSwiftDbAirportsRead, Qt::QueuedConnection);
|
||||
connect(sApp->getWebDataServices(), &CWebDataServices::swiftDbModelMatchingEntitiesRead, this, &ISimulator::onSwiftDbModelMatchingEntitiesRead, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
connect(sApp, &CApplication::aboutToShutdown, this, &ISimulator::unload, Qt::QueuedConnection);
|
||||
|
||||
// info
|
||||
CLogMessage(this).info("Initialized simulator driver: '%1'") << this->getSimulatorInfo().toQString();
|
||||
}
|
||||
|
||||
void ISimulator::onRecalculatedRenderedAircraft(const CAirspaceAircraftSnapshot &snapshot)
|
||||
{
|
||||
if (!snapshot.isValidSnapshot()) { return;}
|
||||
|
||||
// for unrestricted values all add/remove actions are directly linked
|
||||
// when changing back from restricted->unrestricted an one time update is required
|
||||
if (!snapshot.isRestricted() && !snapshot.isRestrictionChanged()) { return; }
|
||||
|
||||
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "Needs to run in object thread");
|
||||
Q_ASSERT_X(snapshot.generatingThreadName() != QThread::currentThread()->objectName(), Q_FUNC_INFO, "Expect snapshot from background thread");
|
||||
|
||||
// restricted snapshot values?
|
||||
bool changed = false;
|
||||
if (snapshot.isRenderingEnabled())
|
||||
{
|
||||
const CCallsignSet callsignsInSimulator(this->physicallyRenderedAircraft()); // state in simulator
|
||||
const CCallsignSet callsignsToBeRemoved(callsignsInSimulator.difference(snapshot.getEnabledAircraftCallsignsByDistance()));
|
||||
const CCallsignSet callsignsToBeAdded(snapshot.getEnabledAircraftCallsignsByDistance().difference(callsignsInSimulator));
|
||||
if (!callsignsToBeRemoved.isEmpty())
|
||||
{
|
||||
const int r = this->physicallyRemoveMultipleRemoteAircraft(callsignsToBeRemoved);
|
||||
changed = r > 0;
|
||||
}
|
||||
|
||||
if (!callsignsToBeAdded.isEmpty())
|
||||
{
|
||||
CSimulatedAircraftList aircraftToBeAdded(this->getAircraftInRange().findByCallsigns(callsignsToBeAdded)); // thread safe copy
|
||||
for (const CSimulatedAircraft &aircraft : aircraftToBeAdded)
|
||||
{
|
||||
Q_ASSERT_X(aircraft.isEnabled(), Q_FUNC_INFO, "Disabled aircraft detected as to be added");
|
||||
Q_ASSERT_X(aircraft.hasModelString(), Q_FUNC_INFO, "Missing model string");
|
||||
this->callPhysicallyAddRemoteAircraft(aircraft); // recalcuate snapshot
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no rendering at all, we remove everything
|
||||
const int r = this->physicallyRemoveAllRemoteAircraft();
|
||||
changed = r > 0;
|
||||
}
|
||||
|
||||
// we have handled snapshot
|
||||
if (changed)
|
||||
{
|
||||
emit this->airspaceSnapshotHandled();
|
||||
}
|
||||
}
|
||||
|
||||
int ISimulator::physicallyRemoveMultipleRemoteAircraft(const CCallsignSet &callsigns)
|
||||
{
|
||||
if (callsigns.isEmpty()) { return 0; }
|
||||
this->stopHighlighting();
|
||||
int removed = 0;
|
||||
for (const CCallsign &callsign : callsigns)
|
||||
{
|
||||
this->callPhysicallyRemoveRemoteAircraft(callsign);
|
||||
removed++;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
int ISimulator::physicallyRemoveAllRemoteAircraft()
|
||||
{
|
||||
// a default implementation, but normally overridden by the sims
|
||||
const CCallsignSet callsigns = this->getAircraftInRangeCallsigns();
|
||||
const int r = this->physicallyRemoveMultipleRemoteAircraft(callsigns);
|
||||
this->debugVerifyStateAfterAllAircraftRemoved();
|
||||
this->clearAllRemoteAircraftData();
|
||||
return r;
|
||||
}
|
||||
|
||||
CAirportList ISimulator::getWebServiceAirports() const
|
||||
{
|
||||
if (this->isShuttingDown()) { return CAirportList(); }
|
||||
if (!sApp->hasWebDataServices()) { return CAirportList(); }
|
||||
return sApp->getWebDataServices()->getAirports();
|
||||
}
|
||||
|
||||
CAirport ISimulator::getWebServiceAirport(const CAirportIcaoCode &icao) const
|
||||
{
|
||||
if (this->isShuttingDown()) { return CAirport(); }
|
||||
if (!sApp->hasWebDataServices()) { return CAirport(); }
|
||||
return sApp->getWebDataServices()->getAirports().findFirstByIcao(icao);
|
||||
}
|
||||
|
||||
int ISimulator::maxAirportsInRange() const
|
||||
{
|
||||
// might change in future or become a setting or such
|
||||
return 20;
|
||||
}
|
||||
|
||||
void ISimulator::onSwiftDbAllDataRead()
|
||||
{
|
||||
// void, can be overridden in specialized drivers
|
||||
}
|
||||
|
||||
void ISimulator::onSwiftDbModelMatchingEntitiesRead()
|
||||
{
|
||||
// void, can be overridden in specialized drivers
|
||||
}
|
||||
|
||||
void ISimulator::onSwiftDbAirportsRead()
|
||||
{
|
||||
// void, can be overridden in specialized drivers
|
||||
}
|
||||
|
||||
void ISimulator::rememberElevationAndCG(const CCallsign &callsign, const QString &modelString, const Geo::CElevationPlane &elevation, const CLength &cg)
|
||||
@@ -145,7 +739,6 @@ namespace BlackCore
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool ISimulator::setInterpolationSetupGlobal(const CInterpolationAndRenderingSetupGlobal &setup)
|
||||
{
|
||||
if (!IInterpolationSetupProvider::setInterpolationSetupGlobal(setup)) { return false; }
|
||||
@@ -156,6 +749,322 @@ namespace BlackCore
|
||||
return true;
|
||||
}
|
||||
|
||||
CAirportList ISimulator::getAirportsInRange() const
|
||||
{
|
||||
// default implementation
|
||||
if (this->isShuttingDown()) { return CAirportList(); }
|
||||
if (!sApp || !sApp->hasWebDataServices()) { return CAirportList(); }
|
||||
|
||||
const CAirportList airports = sApp->getWebDataServices()->getAirports();
|
||||
if (airports.isEmpty()) { return airports; }
|
||||
const CCoordinateGeodetic ownPosition = this->getOwnAircraftPosition();
|
||||
CAirportList airportInRange = airports.findClosest(maxAirportsInRange(), ownPosition);
|
||||
if (m_autoCalcAirportDistance) { airportInRange.calculcateAndUpdateRelativeDistanceAndBearing(ownPosition); }
|
||||
return airportInRange;
|
||||
}
|
||||
|
||||
CAircraftModel ISimulator::reverseLookupModel(const CAircraftModel &model)
|
||||
{
|
||||
bool modified = false;
|
||||
const CAircraftModel reverseModel = CDatabaseUtils::consolidateOwnAircraftModelWithDbData(model, false, &modified);
|
||||
return reverseModel;
|
||||
}
|
||||
|
||||
bool ISimulator::isUpdateAircraftLimited(qint64 timestamp)
|
||||
{
|
||||
if (!m_limitUpdateAircraft) { return false; }
|
||||
const bool hasToken = m_limitUpdateAircraftBucket.tryConsume(1, timestamp);
|
||||
return !hasToken;
|
||||
}
|
||||
|
||||
bool ISimulator::isUpdateAircraftLimitedWithStats(qint64 startTime)
|
||||
{
|
||||
const bool limited = this->isUpdateAircraftLimited(startTime);
|
||||
this->setStatsRemoteAircraftUpdate(startTime, limited);
|
||||
return limited;
|
||||
}
|
||||
|
||||
bool ISimulator::limitToUpdatesPerSecond(int numberPerSecond)
|
||||
{
|
||||
if (numberPerSecond < 1)
|
||||
{
|
||||
m_limitUpdateAircraft = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
int tokens = 0.1 * numberPerSecond; // 100ms
|
||||
do
|
||||
{
|
||||
if (tokens >= 3) { m_limitUpdateAircraftBucket.setInterval(100); break; }
|
||||
tokens = 0.25 * numberPerSecond; // 250ms
|
||||
if (tokens >= 3) { m_limitUpdateAircraftBucket.setInterval(250); break; }
|
||||
tokens = 0.5 * numberPerSecond; // 500ms
|
||||
if (tokens >= 3) { m_limitUpdateAircraftBucket.setInterval(500); break; }
|
||||
tokens = numberPerSecond;
|
||||
m_limitUpdateAircraftBucket.setInterval(1000);
|
||||
}
|
||||
while (false);
|
||||
|
||||
m_limitUpdateAircraftBucket.setCapacityAndTokensToRefill(tokens);
|
||||
m_limitUpdateAircraft = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
QString ISimulator::updateAircraftLimitationInfo() const
|
||||
{
|
||||
if (!m_limitUpdateAircraft) { return QStringLiteral("not limited"); }
|
||||
static const QString limInfo("Limited %1 times with %2/secs.");
|
||||
return limInfo.arg(m_statsUpdateAircraftLimited).arg(m_limitUpdateAircraftBucket.getTokensPerSecond());
|
||||
}
|
||||
|
||||
void ISimulator::resetLastSentValues()
|
||||
{
|
||||
m_lastSentParts.clear();
|
||||
m_lastSentSituations.clear();
|
||||
}
|
||||
|
||||
void ISimulator::resetLastSentValues(const CCallsign &callsign)
|
||||
{
|
||||
m_lastSentParts.remove(callsign);
|
||||
m_lastSentSituations.remove(callsign);
|
||||
}
|
||||
|
||||
void ISimulator::unload()
|
||||
{
|
||||
this->disconnectFrom(); // disconnect from simulator
|
||||
m_remoteAircraftProviderConnections.disconnectAll(); // disconnect signals from provider
|
||||
}
|
||||
|
||||
bool ISimulator::disconnectFrom()
|
||||
{
|
||||
// supposed to be overridden
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ISimulator::logicallyReAddRemoteAircraft(const CCallsign &callsign)
|
||||
{
|
||||
if (this->isShuttingDown()) { return false; }
|
||||
if (callsign.isEmpty()) { return false; }
|
||||
this->stopHighlighting();
|
||||
this->logicallyRemoveRemoteAircraft(callsign);
|
||||
if (!this->isAircraftInRange(callsign)) { return false; }
|
||||
const QPointer<ISimulator> myself(this);
|
||||
QTimer::singleShot(2500, this, [ = ]
|
||||
{
|
||||
if (myself.isNull()) { return; }
|
||||
if (this->isShuttingDown()) { return; }
|
||||
if (!this->isAircraftInRange(callsign)) { return; }
|
||||
const CSimulatedAircraft aircraft = this->getAircraftInRangeForCallsign(callsign);
|
||||
if (aircraft.isEnabled() && aircraft.hasModelString())
|
||||
{
|
||||
this->logicallyAddRemoteAircraft(aircraft);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
CCallsignSet ISimulator::unrenderedEnabledAircraft() const
|
||||
{
|
||||
const CSimulatedAircraftList aircraft = this->getAircraftInRange().findByEnabled(true);
|
||||
if (aircraft.isEmpty()) { return CCallsignSet(); }
|
||||
CCallsignSet enabledOnes = aircraft.getCallsigns();
|
||||
const CCallsignSet renderedOnes = this->physicallyRenderedAircraft();
|
||||
enabledOnes.remove(renderedOnes);
|
||||
return enabledOnes;
|
||||
}
|
||||
|
||||
CCallsignSet ISimulator::renderedDisabledAircraft() const
|
||||
{
|
||||
const CSimulatedAircraftList aircraft = this->getAircraftInRange().findByEnabled(false);
|
||||
if (aircraft.isEmpty()) { return CCallsignSet(); }
|
||||
const CCallsignSet disabledOnes = aircraft.getCallsigns();
|
||||
const CCallsignSet renderedOnes = this->physicallyRenderedAircraft();
|
||||
return renderedOnes.intersection(disabledOnes);
|
||||
}
|
||||
|
||||
bool ISimulator::changeRemoteAircraftEnabled(const CSimulatedAircraft &aircraft)
|
||||
{
|
||||
if (this->isShuttingDown()) { return false; }
|
||||
return aircraft.isEnabled() ?
|
||||
this->physicallyAddRemoteAircraft(aircraft) :
|
||||
this->physicallyRemoveRemoteAircraft(aircraft.getCallsign());
|
||||
}
|
||||
|
||||
bool ISimulator::changeRemoteAircraftModel(const CSimulatedAircraft &aircraft)
|
||||
{
|
||||
// we expect the new model "in aircraft"
|
||||
// remove upfront, and then enable / disable again
|
||||
if (this->isShuttingDown()) { return false; }
|
||||
const CCallsign callsign = aircraft.getCallsign();
|
||||
if (!this->isPhysicallyRenderedAircraft(callsign)) { return false; }
|
||||
this->physicallyRemoveRemoteAircraft(callsign);
|
||||
return this->changeRemoteAircraftEnabled(aircraft);
|
||||
}
|
||||
|
||||
CStatusMessageList ISimulator::debugVerifyStateAfterAllAircraftRemoved() const
|
||||
{
|
||||
CStatusMessageList msgs;
|
||||
if (!CBuildConfig::isLocalDeveloperDebugBuild()) { return msgs; }
|
||||
if (!m_addAgainAircraftWhenRemoved.isEmpty()) { msgs.push_back(CStatusMessage(this).error("m_addAgainAircraftWhenRemoved not empty: '%1'") << m_addAgainAircraftWhenRemoved.getCallsignStrings(true).join(", ")); }
|
||||
return msgs;
|
||||
}
|
||||
|
||||
QString ISimulator::getInvalidSituationLogMessage(const CCallsign &callsign, const CInterpolationStatus &status, const QString &details) const
|
||||
{
|
||||
static const QString msg("CS: '%1' Interpolation: '%2'");
|
||||
const QString m = msg.arg(callsign.asString(), status.toQString());
|
||||
if (details.isEmpty()) { return m; }
|
||||
|
||||
static const QString addDetails(" details: '%1'");
|
||||
return m + addDetails.arg(details);
|
||||
}
|
||||
|
||||
bool ISimulator::clampedLog(const CCallsign &callsign, const CStatusMessage &message)
|
||||
{
|
||||
if (message.isEmpty()) { return false; }
|
||||
constexpr qint64 Timeout = 2000;
|
||||
const qint64 clampTs = m_clampedLogMsg.value(callsign, -1);
|
||||
const qint64 ts = QDateTime::currentMSecsSinceEpoch();
|
||||
if (clampTs > 0 && ((clampTs + Timeout) > ts)) { return false; }
|
||||
CLogMessage::preformatted(message);
|
||||
m_clampedLogMsg[callsign] = ts;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ISimulator::removedClampedLog(const CCallsign &callsign)
|
||||
{
|
||||
m_clampedLogMsg.remove(callsign);
|
||||
}
|
||||
|
||||
void ISimulator::setStatsRemoteAircraftUpdate(qint64 startTime, bool limited)
|
||||
{
|
||||
const qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
const qint64 dt = now - startTime;
|
||||
m_statsCurrentUpdateTimeMs = dt;
|
||||
m_statsUpdateAircraftTimeTotalMs += dt;
|
||||
m_statsUpdateAircraftRuns++;
|
||||
m_statsUpdateAircraftTimeAvgMs = static_cast<double>(m_statsUpdateAircraftTimeTotalMs) / static_cast<double>(m_statsUpdateAircraftRuns);
|
||||
m_updateRemoteAircraftInProgress = false;
|
||||
m_statsLastUpdateAircraftRequestedMs = startTime;
|
||||
|
||||
if (m_statsMaxUpdateTimeMs < dt) { m_statsMaxUpdateTimeMs = dt; }
|
||||
if (m_statsLastUpdateAircraftRequestedMs > 0) { m_statsUpdateAircraftRequestedDeltaMs = startTime - m_statsLastUpdateAircraftRequestedMs; }
|
||||
if (limited) { m_statsUpdateAircraftLimited++; }
|
||||
}
|
||||
|
||||
QString ISimulator::latestLoggedDataFormatted(const CCallsign &cs) const
|
||||
{
|
||||
const SituationLog s = m_interpolationLogger.getLastSituationLog(cs);
|
||||
const PartsLog p = m_interpolationLogger.getLastPartsLog(cs);
|
||||
|
||||
static const QString sep("\n------\n");
|
||||
QString dm;
|
||||
if (s.tsCurrent > 0)
|
||||
{
|
||||
dm = QStringLiteral("Setup: ") % s.usedSetup.toQString(true) %
|
||||
QStringLiteral("\n\n") %
|
||||
QStringLiteral("Situation: ") % s.toQString(false, true, true, true, true, sep);
|
||||
}
|
||||
if (p.tsCurrent > 0) { dm += (dm.isEmpty() ? QStringLiteral("") : QStringLiteral("\n\n")) % QStringLiteral("Parts: ") % p.toQString(sep); }
|
||||
return dm;
|
||||
}
|
||||
|
||||
void ISimulator::rapOnRecalculatedRenderedAircraft(const CAirspaceAircraftSnapshot &snapshot)
|
||||
{
|
||||
if (!this->isConnected()) { return; }
|
||||
if (this->isShuttingDown()) { return; }
|
||||
this->onRecalculatedRenderedAircraft(snapshot);
|
||||
}
|
||||
|
||||
void ISimulator::rapOnRemoteProviderRemovedAircraft(const CCallsign &callsign)
|
||||
{
|
||||
Q_UNUSED(callsign);
|
||||
// currently not used, the calls are handled by context call logicallyRemoveRemoteAircraft
|
||||
}
|
||||
|
||||
void ISimulator::callPhysicallyAddRemoteAircraft(const CSimulatedAircraft &remoteAircraft)
|
||||
{
|
||||
m_statsPhysicallyAddedAircraft++;
|
||||
this->physicallyAddRemoteAircraft(remoteAircraft);
|
||||
}
|
||||
|
||||
void ISimulator::callPhysicallyRemoveRemoteAircraft(const CCallsign &remoteCallsign, bool blinking)
|
||||
{
|
||||
if (!blinking) { this->clearData(remoteCallsign); }
|
||||
this->physicallyRemoveRemoteAircraft(remoteCallsign);
|
||||
}
|
||||
|
||||
void ISimulator::displayLoggedSituationInSimulator(const CCallsign &cs, bool stopLogging, int times)
|
||||
{
|
||||
if (cs.isEmpty()) { return; }
|
||||
if (this->isShuttingDown()) { return; }
|
||||
const CInterpolationAndRenderingSetupPerCallsign setup = this->getInterpolationSetupPerCallsignOrDefault(cs);
|
||||
const bool logsCs = setup.logInterpolation();
|
||||
if (!logsCs) { return; }
|
||||
|
||||
stopLogging = stopLogging || !this->isSimulating(); // stop when sim was stopped
|
||||
stopLogging = stopLogging && logsCs;
|
||||
if (!stopLogging && times < 1) { return; }
|
||||
|
||||
const bool inRange = this->getAircraftInRangeCallsigns().contains(cs);
|
||||
if (!stopLogging && !inRange) { return; }
|
||||
if (stopLogging && (times < 1 || !inRange))
|
||||
{
|
||||
this->setLogCallsign(false, cs);
|
||||
return;
|
||||
}
|
||||
|
||||
const QString dm = this->latestLoggedDataFormatted(cs);
|
||||
if (!dm.isEmpty())
|
||||
{
|
||||
this->displayStatusMessage(CStatusMessage(this).info(dm));
|
||||
emit this->requestUiConsoleMessage(dm, true);
|
||||
}
|
||||
|
||||
const int t = 4500 + (qrand() % 1000); // makes sure not always using the same time difference
|
||||
const QPointer<ISimulator> myself(this);
|
||||
QTimer::singleShot(t, this, [ = ]
|
||||
{
|
||||
if (myself.isNull() || myself->isShuttingDown()) { return; }
|
||||
this->displayLoggedSituationInSimulator(cs, stopLogging, times - 1);
|
||||
});
|
||||
}
|
||||
|
||||
void ISimulator::reverseLookupAndUpdateOwnAircraftModel(const QString &modelString)
|
||||
{
|
||||
CAircraftModel model = getOwnAircraftModel();
|
||||
model.setModelString(modelString);
|
||||
this->reverseLookupAndUpdateOwnAircraftModel(model);
|
||||
}
|
||||
|
||||
void ISimulator::reverseLookupAndUpdateOwnAircraftModel(const BlackMisc::Simulation::CAircraftModel &model)
|
||||
{
|
||||
Q_ASSERT_X(sApp, Q_FUNC_INFO, "Missing sApp");
|
||||
Q_ASSERT_X(sApp->hasWebDataServices(), Q_FUNC_INFO, "Missing web services");
|
||||
|
||||
if (!model.hasModelString()) { return; }
|
||||
if (this->getOwnAircraftModel() != model)
|
||||
{
|
||||
if (CDatabaseUtils::hasDbAircraftData())
|
||||
{
|
||||
const CAircraftModel newModel = this->reverseLookupModel(model);
|
||||
const bool updated = this->updateOwnModel(newModel); // update in provider (normally the context)
|
||||
if (updated)
|
||||
{
|
||||
emit this->ownAircraftModelChanged(this->getOwnAircraftModel());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we wait for the data
|
||||
connect(sApp->getWebDataServices(), &CWebDataServices::swiftDbModelMatchingEntitiesRead, this, [ = ]
|
||||
{
|
||||
this->reverseLookupAndUpdateOwnAircraftModel(model);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ISimulatorListener::ISimulatorListener(const CSimulatorPluginInfo &info) :
|
||||
QObject(), m_info(info)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "blackcore/application.h"
|
||||
#include "blackcore/blackcoreexport.h"
|
||||
#include "blackmisc/simulation/settings/simulatorsettings.h"
|
||||
#include "blackmisc/simulation/aircraftmodellist.h"
|
||||
#include "blackmisc/simulation/simulatedaircraft.h"
|
||||
#include "blackmisc/simulation/simulatorplugininfo.h"
|
||||
@@ -35,6 +36,7 @@
|
||||
#include "blackmisc/identifier.h"
|
||||
#include "blackmisc/pixmap.h"
|
||||
#include "blackmisc/simplecommandparser.h"
|
||||
#include "blackmisc/tokenbucket.h"
|
||||
#include "blackconfig/buildconfig.h"
|
||||
|
||||
#include <QFlags>
|
||||
@@ -77,11 +79,14 @@ namespace BlackCore
|
||||
Q_DECLARE_FLAGS(SimulatorStatus, SimulatorStatusFlag)
|
||||
Q_FLAG(SimulatorStatus)
|
||||
|
||||
//! Log categories
|
||||
static const BlackMisc::CLogCategoryList &getLogCategories();
|
||||
|
||||
//! Render all aircraft if number of aircraft >= MaxAircraftInfinite
|
||||
const int MaxAircraftInfinite = 100;
|
||||
|
||||
//! Destructor
|
||||
virtual ~ISimulator() {}
|
||||
virtual ~ISimulator();
|
||||
|
||||
//! Combined status
|
||||
virtual SimulatorStatus getSimulatorStatus() const;
|
||||
@@ -90,7 +95,7 @@ namespace BlackCore
|
||||
virtual bool isTimeSynchronized() const = 0;
|
||||
|
||||
//! Get the setup (simulator environment)
|
||||
virtual const BlackMisc::Simulation::CSimulatorInternals &getSimulatorInternals() const = 0;
|
||||
virtual const BlackMisc::Simulation::CSimulatorInternals &getSimulatorInternals() const { return m_simulatorInternals; }
|
||||
|
||||
//! Connect to simulator
|
||||
virtual bool connectTo() = 0;
|
||||
@@ -98,31 +103,31 @@ namespace BlackCore
|
||||
//! Disconnect from simulator
|
||||
virtual bool disconnectFrom() = 0;
|
||||
|
||||
//! Logically add a new aircraft. Depending on max. aircraft, enabled status etc.
|
||||
//! it will physically added to the simulator.
|
||||
//! Logically add a new aircraft.
|
||||
//! Depending on max. aircraft, enabled status etc. it will physically added to the simulator.
|
||||
//! \sa physicallyAddRemoteAircraft
|
||||
virtual bool logicallyAddRemoteAircraft(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft) = 0;
|
||||
virtual bool logicallyAddRemoteAircraft(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft);
|
||||
|
||||
//! Logically remove remote aircraft from simulator. Depending on max. aircraft, enabled status etc.
|
||||
//! it will physically added to the simulator.
|
||||
virtual bool logicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) = 0;
|
||||
//! Logically remove remote aircraft from simulator.
|
||||
//! Depending on max. aircraft, enabled status etc. it will physically added to the simulator.
|
||||
virtual bool logicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Removes and adds again the aircraft
|
||||
//! \sa logicallyRemoveRemoteAircraft
|
||||
//! \sa logicallyAddRemoteAircraft
|
||||
virtual bool logicallyReAddRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) = 0;
|
||||
virtual bool logicallyReAddRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Find the unrendered enabled aircraft
|
||||
virtual BlackMisc::Aviation::CCallsignSet unrenderedEnabledAircraft() const = 0;
|
||||
virtual BlackMisc::Aviation::CCallsignSet unrenderedEnabledAircraft() const;
|
||||
|
||||
//! Find the rendered disabled aircraft
|
||||
virtual BlackMisc::Aviation::CCallsignSet renderedDisabledAircraft() const = 0;
|
||||
virtual BlackMisc::Aviation::CCallsignSet renderedDisabledAircraft() const;
|
||||
|
||||
//! Change remote aircraft per property
|
||||
virtual bool changeRemoteAircraftModel(const BlackMisc::Simulation::CSimulatedAircraft &aircraft) = 0;
|
||||
virtual bool changeRemoteAircraftModel(const BlackMisc::Simulation::CSimulatedAircraft &aircraft);
|
||||
|
||||
//! Aircraft got enabled / disabled
|
||||
virtual bool changeRemoteAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft) = 0;
|
||||
virtual bool changeRemoteAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft);
|
||||
|
||||
//! Update own aircraft cockpit (usually from context)
|
||||
virtual bool updateOwnSimulatorCockpit(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const BlackMisc::CIdentifier &originator) = 0;
|
||||
@@ -137,7 +142,7 @@ namespace BlackCore
|
||||
virtual void displayTextMessage(const BlackMisc::Network::CTextMessage &message) const = 0;
|
||||
|
||||
//! Airports in range from simulator, or if not available from web service
|
||||
virtual BlackMisc::Aviation::CAirportList getAirportsInRange() const = 0;
|
||||
virtual BlackMisc::Aviation::CAirportList getAirportsInRange() const;
|
||||
|
||||
//! Set time synchronization between simulator and user's computer time
|
||||
//! \remarks not all drivers implement this, e.g. if it is an intrinsic simulator feature
|
||||
@@ -155,20 +160,19 @@ namespace BlackCore
|
||||
virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const = 0;
|
||||
|
||||
//! Highlight the aircraft for given time (or disable highlight)
|
||||
virtual void highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime) = 0;
|
||||
virtual void highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime);
|
||||
|
||||
//! Follow aircraft
|
||||
virtual bool followAircraft(const BlackMisc::Aviation::CCallsign &callsign)
|
||||
{
|
||||
Q_UNUSED(callsign);
|
||||
return false;
|
||||
}
|
||||
virtual bool followAircraft(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Activates or deactivates simulator weather
|
||||
virtual void setWeatherActivated(bool activated) = 0;
|
||||
virtual void setWeatherActivated(bool activated);
|
||||
|
||||
//! Reload weather settings
|
||||
void reloadWeatherSettings();
|
||||
|
||||
//! Driver will be unloaded
|
||||
virtual void unload() = 0;
|
||||
virtual void unload();
|
||||
|
||||
//! Are we connected to the simulator?
|
||||
virtual bool isConnected() const = 0;
|
||||
@@ -180,11 +184,11 @@ namespace BlackCore
|
||||
virtual bool isSimulating() const { return this->isConnected(); }
|
||||
|
||||
//! Clear all aircraft related data
|
||||
virtual void clearAllRemoteAircraftData() = 0;
|
||||
virtual void clearAllRemoteAircraftData();
|
||||
|
||||
//! Debug function to check state after all aircraft have been removed
|
||||
//! \remarks only in local developer builds
|
||||
virtual BlackMisc::CStatusMessageList debugVerifyStateAfterAllAircraftRemoved() const = 0;
|
||||
virtual BlackMisc::CStatusMessageList debugVerifyStateAfterAllAircraftRemoved() const;
|
||||
|
||||
//! Is overall (swift) application shutting down
|
||||
//! \threadsafe
|
||||
@@ -206,7 +210,7 @@ namespace BlackCore
|
||||
virtual QString getStatisticsSimulatorSpecific() const { return QString(); }
|
||||
|
||||
//! Reset the statistics
|
||||
virtual void resetAircraftStatistics() {}
|
||||
virtual void resetAircraftStatistics();
|
||||
|
||||
//! \copydoc BlackMisc::IProvider::asQObject
|
||||
virtual QObject *asQObject() override { return this; }
|
||||
@@ -214,12 +218,23 @@ namespace BlackCore
|
||||
//! \addtogroup swiftdotcommands
|
||||
//! @{
|
||||
//! <pre>
|
||||
//! .drv unload unload driver BlackCore::CSimulatorCommon
|
||||
//! .drv fsuipc on|off enable/disable FSUIPC (if applicable) BlackSimPlugin::FsCommon::CSimulatorFsCommon
|
||||
//! .drv unload unload plugin BlackCore::ISimulator
|
||||
//! .drv limit number limit the number of updates BlackCore::ISimulator
|
||||
//! .drv logint callsign log interpolator for callsign BlackCore::ISimulator
|
||||
//! .drv logint off no log information for interpolator BlackCore::ISimulator
|
||||
//! .drv logint write write interpolator log to file BlackCore::ISimulator
|
||||
//! .drv logint clear clear current log BlackCore::ISimulator
|
||||
//! .drv pos callsign shows current position in simulator BlackCore::ISimulator
|
||||
//! .drv spline|linear callsign interpolator spline or linear BlackCore::ISimulator
|
||||
//! .drv aircraft readd callsign re-add (add again) aircraft BlackCore::ISimulator
|
||||
//! .drv aircraft readd all re-add all aircraft BlackCore::ISimulator
|
||||
//! .drv aircraft rm callsign remove aircraft BlackCore::ISimulator
|
||||
//! .drv unload unload driver BlackCore::ISimulator
|
||||
//! .drv fsuipc on|off enable/disable FSUIPC (if applicable) BlackSimPlugin::FsCommon::CSimulatorFsCommon
|
||||
//! </pre>
|
||||
//! @}
|
||||
//! Parse command line
|
||||
virtual bool parseCommandLine(const QString &commandLine, const BlackMisc::CIdentifier &originator) = 0;
|
||||
//! Parse command line for simulator drivers, derived classes can add specific parsing by overriding ISimulator::parseDetails
|
||||
virtual bool parseCommandLine(const QString &commandLine, const BlackMisc::CIdentifier &originator);
|
||||
|
||||
//! Consolidate setup with other data like from BlackMisc::Simulation::IRemoteAircraftProvider
|
||||
//! \threadsafe
|
||||
@@ -228,6 +243,46 @@ namespace BlackCore
|
||||
//! \copydoc BlackMisc::Simulation::IInterpolationSetupProvider::setInterpolationSetupGlobal
|
||||
virtual bool setInterpolationSetupGlobal(const BlackMisc::Simulation::CInterpolationAndRenderingSetupGlobal &setup) override;
|
||||
|
||||
//! Counter added aircraft
|
||||
int getStatisticsPhysicallyAddedAircraft() const { return m_statsPhysicallyAddedAircraft; }
|
||||
|
||||
//! Counter removed aircraft
|
||||
int getStatisticsPhysicallyRemovedAircraft() const { return m_statsPhysicallyRemovedAircraft; }
|
||||
|
||||
//! Current update time in ms
|
||||
double getStatisticsCurrentUpdateTimeMs() const { return m_statsCurrentUpdateTimeMs; }
|
||||
|
||||
//! Average update time in ms
|
||||
double getStatisticsAverageUpdateTimeMs() const { return m_statsUpdateAircraftTimeAvgMs; }
|
||||
|
||||
//! Total update time in ms
|
||||
qint64 getStatisticsTotalUpdateTimeMs() const { return m_statsUpdateAircraftTimeTotalMs; }
|
||||
|
||||
//! Max.update time in ms
|
||||
qint64 getStatisticsMaxUpdateTimeMs() const { return m_statsMaxUpdateTimeMs; }
|
||||
|
||||
//! Number of update runs
|
||||
int getStatisticsUpdateRuns() const { return m_statsUpdateAircraftRuns; }
|
||||
|
||||
//! Time between two update requests
|
||||
qint64 getStatisticsAircraftUpdatedRequestedDeltaMs() const { return m_statsUpdateAircraftRequestedDeltaMs; }
|
||||
|
||||
//! Access to logger
|
||||
const BlackMisc::Simulation::CInterpolationLogger &interpolationLogger() const { return m_interpolationLogger; }
|
||||
|
||||
//! The latest logged data formatted
|
||||
//! \remark public only for log. displays
|
||||
QString latestLoggedDataFormatted(const BlackMisc::Aviation::CCallsign &cs) const;
|
||||
|
||||
//! Info about update aircraft limitations
|
||||
QString updateAircraftLimitationInfo() const;
|
||||
|
||||
//! Reset the last sent values
|
||||
void resetLastSentValues();
|
||||
|
||||
//! Reset the last sent values per callsign
|
||||
void resetLastSentValues(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Register help
|
||||
static void registerHelp();
|
||||
|
||||
@@ -280,6 +335,31 @@ namespace BlackCore
|
||||
BlackMisc::Network::IClientProvider *clientProvider,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
//! \name When swift DB data are read
|
||||
//! @{
|
||||
virtual void onSwiftDbAllDataRead();
|
||||
virtual void onSwiftDbModelMatchingEntitiesRead();
|
||||
virtual void onSwiftDbAirportsRead();
|
||||
//! @}
|
||||
|
||||
//! Parsed in derived classes
|
||||
virtual bool parseDetails(const BlackMisc::CSimpleCommandParser &parser) = 0;
|
||||
|
||||
//! Airports from web services
|
||||
BlackMisc::Aviation::CAirportList getWebServiceAirports() const;
|
||||
|
||||
//! Airport from web services by ICAO code
|
||||
BlackMisc::Aviation::CAirport getWebServiceAirport(const BlackMisc::Aviation::CAirportIcaoCode &icao) const;
|
||||
|
||||
//! Max.airports in range
|
||||
int maxAirportsInRange() const;
|
||||
|
||||
//! \name Connected with remote aircraft provider signals
|
||||
//! @{
|
||||
//! Recalculate the rendered aircraft, this happens when restrictions are applied (max. aircraft, range)
|
||||
virtual void onRecalculatedRenderedAircraft(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &snapshot);
|
||||
//! @}
|
||||
|
||||
//! Add new remote aircraft physically to the simulator
|
||||
//! \sa changeRemoteAircraftEnabled to hide a remote aircraft
|
||||
virtual bool physicallyAddRemoteAircraft(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft) = 0;
|
||||
@@ -288,7 +368,7 @@ namespace BlackCore
|
||||
virtual bool physicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) = 0;
|
||||
|
||||
//! Remove remote aircraft from simulator
|
||||
virtual int physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns) = 0;
|
||||
virtual int physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns);
|
||||
|
||||
//! Remove all remote aircraft
|
||||
virtual int physicallyRemoveAllRemoteAircraft() = 0;
|
||||
@@ -301,8 +381,153 @@ namespace BlackCore
|
||||
//! \sa simulatorStatusChanged;
|
||||
void emitSimulatorCombinedStatus(SimulatorStatus oldStatus = Unspecified);
|
||||
|
||||
//! Emit the signal
|
||||
//! \copydoc BlackMisc::Simulation::IInterpolationSetupProvider::emitInterpolationSetupChanged
|
||||
virtual void emitInterpolationSetupChanged() override;
|
||||
|
||||
//! Display a debug log message based on BlackMisc::Simulation::CInterpolationAndRenderingSetup
|
||||
//! remark shows log messages of functions calls
|
||||
void debugLogMessage(const QString &msg);
|
||||
|
||||
//! Display a debug log message based on BlackMisc::Simulation::CInterpolationAndRenderingSetup
|
||||
//! remark shows log messages of functions calls
|
||||
void debugLogMessage(const QString &funcInfo, const QString &msg);
|
||||
|
||||
//! Show log messages?
|
||||
bool showDebugLogMessage() const;
|
||||
|
||||
//! Restore aircraft from the provider data
|
||||
void resetAircraftFromProvider(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Clear the related data as statistics etc.
|
||||
virtual void clearData(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Full reset of state
|
||||
//! \remark reset as it was unloaded without unloading
|
||||
//! \sa ISimulator::clearAllRemoteAircraftData
|
||||
virtual void reset();
|
||||
|
||||
//! Reset highlighting
|
||||
void resetHighlighting();
|
||||
|
||||
//! Restore all highlighted aircraft
|
||||
void stopHighlighting();
|
||||
|
||||
//! Slow timer used to highlight aircraft, can be used for other things too
|
||||
virtual void oneSecondTimerTimeout();
|
||||
|
||||
//! Kill timer if id is valid
|
||||
void safeKillTimer();
|
||||
|
||||
//! Inject weather grid to simulator
|
||||
virtual void injectWeatherGrid(const BlackMisc::Weather::CWeatherGrid &weatherGrid);
|
||||
|
||||
//! Blink the highlighted aircraft
|
||||
void blinkHighlightedAircraft();
|
||||
|
||||
//! Equal to last sent situation
|
||||
bool isEqualLastSent(const BlackMisc::Aviation::CAircraftSituation &compare) const;
|
||||
|
||||
//! Equal to last sent situation
|
||||
bool isEqualLastSent(const BlackMisc::Aviation::CAircraftParts &compare, const BlackMisc::Aviation::CCallsign &callsign) const;
|
||||
|
||||
//! Remember as last sent
|
||||
void rememberLastSent(const BlackMisc::Aviation::CAircraftSituation &sent);
|
||||
|
||||
//! Remember as last sent
|
||||
void rememberLastSent(const BlackMisc::Aviation::CAircraftParts &sent, const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Last sent situations
|
||||
BlackMisc::Aviation::CAircraftSituationList getLastSentCanLikelySkipNearGroundInterpolation() const;
|
||||
|
||||
//! Limit reached (max number of updates by token bucket if enabled)
|
||||
bool isUpdateAircraftLimited(qint64 timestamp = -1);
|
||||
|
||||
//! Limited as ISimulator::isUpdateAircraftLimited plus updating statistics
|
||||
bool isUpdateAircraftLimitedWithStats(qint64 startTime = -1);
|
||||
|
||||
//! Limit to updates per second
|
||||
bool limitToUpdatesPerSecond(int numberPerSecond);
|
||||
|
||||
//! Set own model
|
||||
void reverseLookupAndUpdateOwnAircraftModel(const BlackMisc::Simulation::CAircraftModel &model);
|
||||
|
||||
//! Set own model
|
||||
void reverseLookupAndUpdateOwnAircraftModel(const QString &modelString);
|
||||
|
||||
//! Info about invalid situation
|
||||
QString getInvalidSituationLogMessage(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Simulation::CInterpolationStatus &status, const QString &details = {}) const;
|
||||
|
||||
//! Can a new log message be generated without generating a "message" overflow
|
||||
//! \remark works per callsign
|
||||
//! \remark use this function when there is a risk that a lot of log. messages will be generated in a short time
|
||||
bool clampedLog(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::CStatusMessage &message);
|
||||
|
||||
//! Mark as justed logged
|
||||
//! \remark touch, but also return if it can be logged
|
||||
//! \remark use this function when there is a risk that a lot of log. messages will be generated in a short time
|
||||
void removedClampedLog(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Update stats and flags
|
||||
void setStatsRemoteAircraftUpdate(qint64 startTime, bool limited = false);
|
||||
|
||||
//! Lookup against DB data
|
||||
static BlackMisc::Simulation::CAircraftModel reverseLookupModel(const BlackMisc::Simulation::CAircraftModel &model);
|
||||
|
||||
bool m_pausedSimFreezesInterpolation = false; //!< paused simulator will also pause interpolation (so AI aircraft will hold)
|
||||
bool m_autoCalcAirportDistance = true; //!< automatically calculate airport distance and bearing
|
||||
bool m_updateRemoteAircraftInProgress = false; //!< currently updating remote aircraft
|
||||
int m_timerId = -1; //!< dispatch timer id
|
||||
int m_statsUpdateAircraftRuns = 0; //!< statistics update count
|
||||
int m_statsUpdateAircraftLimited = 0; //!< skipped because of max.update limitations
|
||||
double m_statsUpdateAircraftTimeAvgMs = 0; //!< statistics average update time
|
||||
qint64 m_statsUpdateAircraftTimeTotalMs = 0; //!< statistics total update time
|
||||
qint64 m_statsCurrentUpdateTimeMs = 0; //!< statistics current update time
|
||||
qint64 m_statsMaxUpdateTimeMs = 0; //!< statistics max.update time
|
||||
qint64 m_statsLastUpdateAircraftRequestedMs = 0; //!< when was the last aircraft update requested
|
||||
qint64 m_statsUpdateAircraftRequestedDeltaMs = 0; //!< delta time between 2 aircraft updates
|
||||
|
||||
BlackMisc::Simulation::CSimulatorInternals m_simulatorInternals; //!< setup object
|
||||
BlackMisc::Simulation::CInterpolationLogger m_interpolationLogger; //!< log.interpolation
|
||||
BlackMisc::Aviation::CTimestampPerCallsign m_clampedLogMsg; //!< when logged last for this callsign, can be used so there is no log message overflow
|
||||
BlackMisc::Aviation::CAircraftSituationPerCallsign m_lastSentSituations; //!< last situation sent to simulator
|
||||
BlackMisc::Aviation::CAircraftPartsPerCallsign m_lastSentParts; //!< last parts sent to simulator
|
||||
|
||||
// some optional functionality which can be used by the simulators as needed
|
||||
BlackMisc::Simulation::CSimulatedAircraftList m_addAgainAircraftWhenRemoved; //!< add this model again when removed, normally used to change model
|
||||
|
||||
// limit the update aircraft to a maximum per second
|
||||
BlackMisc::CTokenBucket m_limitUpdateAircraftBucket { 5, 100, 5 }; //!< means 50 per second
|
||||
bool m_limitUpdateAircraft = false; //!< limit the update frequency by using BlackMisc::CTokenBucket
|
||||
|
||||
// weather
|
||||
bool m_isWeatherActivated = false; //!< Is simulator weather activated?
|
||||
BlackMisc::Geo::CCoordinateGeodetic m_lastWeatherPosition; //!< Own aircraft position at which weather was fetched and injected last
|
||||
BlackMisc::CSetting<BlackMisc::Simulation::Settings::TSelectedWeatherScenario> m_weatherScenarioSettings { this, &ISimulator::reloadWeatherSettings }; //!< Selected weather scenario
|
||||
|
||||
private:
|
||||
// remote aircraft provider ("rap") bound
|
||||
void rapOnRecalculatedRenderedAircraft(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &snapshot);
|
||||
void rapOnRemoteProviderRemovedAircraft(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
// call with counters updated
|
||||
void callPhysicallyAddRemoteAircraft(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft);
|
||||
void callPhysicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &remoteCallsign, bool blinking = false);
|
||||
|
||||
//! Display a logged situation in simulator
|
||||
void displayLoggedSituationInSimulator(const BlackMisc::Aviation::CCallsign &cs, bool stopLogging, int times = 40);
|
||||
|
||||
bool m_blinkCycle = false; //!< used for highlighting
|
||||
qint64 m_highlightEndTimeMsEpoch = 0; //!< end highlighting
|
||||
int m_timerCounter = 0; //!< allows to calculate n seconds
|
||||
QTimer m_oneSecondTimer; //!< multi purpose timer with 1 sec. interval
|
||||
BlackMisc::Aviation::CCallsignSet m_callsignsToBeRendered; //!< callsigns which will be rendered
|
||||
BlackMisc::CConnectionGuard m_remoteAircraftProviderConnections; //!< connected signal/slots
|
||||
BlackMisc::Simulation::CSimulatedAircraftList m_highlightedAircraft; //!< all other aircraft are to be ignored
|
||||
|
||||
// statistics values of how often those functions are called
|
||||
// those are the added counters, overflow will not be an issue here (discussed in T171 review)
|
||||
int m_statsPhysicallyAddedAircraft = 0; //!< statistics, how many aircraft added
|
||||
int m_statsPhysicallyRemovedAircraft = 0; //!< statistics, how many aircraft removed
|
||||
};
|
||||
|
||||
//! Interface to a simulator listener.
|
||||
|
||||
@@ -1,961 +0,0 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "blackcore/simulatorcommon.h"
|
||||
#include "blackcore/db/databaseutils.h"
|
||||
#include "blackcore/db/databaseutils.h"
|
||||
#include "blackcore/webdataservices.h"
|
||||
#include "blackmisc/aviation/aircraftsituation.h"
|
||||
#include "blackmisc/aviation/callsign.h"
|
||||
#include "blackmisc/simulation/aircraftmodellist.h"
|
||||
#include "blackmisc/simulation/airspaceaircraftsnapshot.h"
|
||||
#include "blackmisc/simulation/interpolator.h"
|
||||
#include "blackmisc/simulation/simulatedaircraft.h"
|
||||
#include "blackmisc/pq/physicalquantity.h"
|
||||
#include "blackmisc/simplecommandparser.h"
|
||||
#include "blackmisc/logmessage.h"
|
||||
#include "blackmisc/statusmessage.h"
|
||||
#include "blackmisc/threadutils.h"
|
||||
#include "blackconfig/buildconfig.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QThread>
|
||||
#include <QDir>
|
||||
#include <QUrl>
|
||||
#include <QDesktopServices>
|
||||
#include <functional>
|
||||
|
||||
using namespace BlackConfig;
|
||||
using namespace BlackMisc;
|
||||
using namespace BlackMisc::Geo;
|
||||
using namespace BlackMisc::Aviation;
|
||||
using namespace BlackMisc::Network;
|
||||
using namespace BlackMisc::Simulation;
|
||||
using namespace BlackMisc::PhysicalQuantities;
|
||||
using namespace BlackMisc::Simulation;
|
||||
using namespace BlackMisc::Weather;
|
||||
using namespace BlackCore::Db;
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
CSimulatorCommon::CSimulatorCommon(const CSimulatorPluginInfo &info,
|
||||
IOwnAircraftProvider *ownAircraftProvider,
|
||||
IRemoteAircraftProvider *remoteAircraftProvider,
|
||||
IWeatherGridProvider *weatherGridProvider,
|
||||
IClientProvider *clientProvider,
|
||||
QObject *parent)
|
||||
: ISimulator(info, ownAircraftProvider, remoteAircraftProvider, weatherGridProvider, clientProvider, parent)
|
||||
{
|
||||
this->setObjectName("Simulator: " + info.getIdentifier());
|
||||
CSimulatorCommon::registerHelp();
|
||||
|
||||
// provider signals, hook up with remote aircraft provider
|
||||
m_remoteAircraftProviderConnections.append(
|
||||
CRemoteAircraftAware::provider()->connectRemoteAircraftProviderSignals(
|
||||
this, // receiver must match object in bind
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::bind(&CSimulatorCommon::rapOnRemoteProviderRemovedAircraft, this, std::placeholders::_1),
|
||||
std::bind(&CSimulatorCommon::rapOnRecalculatedRenderedAircraft, this, std::placeholders::_1))
|
||||
);
|
||||
|
||||
// timer
|
||||
connect(&m_oneSecondTimer, &QTimer::timeout, this, &CSimulatorCommon::oneSecondTimerTimeout);
|
||||
m_oneSecondTimer.setObjectName(this->objectName().append(":m_oneSecondTimer"));
|
||||
m_oneSecondTimer.start(1000);
|
||||
|
||||
// swift data
|
||||
if (sApp && sApp->hasWebDataServices())
|
||||
{
|
||||
connect(sApp->getWebDataServices(), &CWebDataServices::swiftDbAllDataRead, this, &CSimulatorCommon::onSwiftDbAllDataRead, Qt::QueuedConnection);
|
||||
connect(sApp->getWebDataServices(), &CWebDataServices::swiftDbAirportsRead, this, &CSimulatorCommon::onSwiftDbAirportsRead, Qt::QueuedConnection);
|
||||
connect(sApp->getWebDataServices(), &CWebDataServices::swiftDbModelMatchingEntitiesRead, this, &CSimulatorCommon::onSwiftDbModelMatchingEntitiesRead, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
connect(sApp, &CApplication::aboutToShutdown, this, &CSimulatorCommon::unload, Qt::QueuedConnection);
|
||||
|
||||
// info
|
||||
CLogMessage(this).info("Initialized simulator driver: '%1'") << this->getSimulatorInfo().toQString();
|
||||
}
|
||||
|
||||
CSimulatorCommon::~CSimulatorCommon()
|
||||
{
|
||||
this->safeKillTimer();
|
||||
}
|
||||
|
||||
const CLogCategoryList &CSimulatorCommon::getLogCategories()
|
||||
{
|
||||
static const CLogCategoryList cats({ CLogCategory::driver(), CLogCategory::plugin() });
|
||||
return cats;
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::logicallyAddRemoteAircraft(const CSimulatedAircraft &remoteAircraft)
|
||||
{
|
||||
Q_ASSERT_X(remoteAircraft.hasModelString(), Q_FUNC_INFO, "Missing model string");
|
||||
Q_ASSERT_X(remoteAircraft.hasCallsign(), Q_FUNC_INFO, "Missing callsign");
|
||||
|
||||
const bool renderingRestricted = this->getInterpolationSetupGlobal().isRenderingRestricted();
|
||||
if (this->showDebugLogMessage()) { this->debugLogMessage(Q_FUNC_INFO, QString("Restricted: %1 cs: '%2' enabled: %3").arg(boolToYesNo(renderingRestricted), remoteAircraft.getCallsignAsString(), boolToYesNo(remoteAircraft.isEnabled()))); }
|
||||
if (!remoteAircraft.isEnabled()) { return false; }
|
||||
|
||||
// if not restriced, directly change
|
||||
if (!renderingRestricted) { this->callPhysicallyAddRemoteAircraft(remoteAircraft); return true; }
|
||||
|
||||
// restricted -> will be added with next snapshot onRecalculatedRenderedAircraft
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::logicallyRemoveRemoteAircraft(const CCallsign &callsign)
|
||||
{
|
||||
// if not restriced, directly change
|
||||
if (!this->getInterpolationSetupGlobal().isRenderingRestricted())
|
||||
{
|
||||
m_statsPhysicallyAddedAircraft++;
|
||||
this->callPhysicallyRemoveRemoteAircraft(callsign); return true;
|
||||
}
|
||||
|
||||
// will be added with next snapshot onRecalculatedRenderedAircraft
|
||||
return false;
|
||||
}
|
||||
|
||||
int CSimulatorCommon::maxAirportsInRange() const
|
||||
{
|
||||
// might change in future or become a setting or such
|
||||
return 20;
|
||||
}
|
||||
|
||||
void CSimulatorCommon::blinkHighlightedAircraft()
|
||||
{
|
||||
if (m_highlightedAircraft.isEmpty() || m_highlightEndTimeMsEpoch < 1) { return; }
|
||||
if (this->isShuttingDown()) { return; }
|
||||
m_blinkCycle = !m_blinkCycle;
|
||||
|
||||
if (QDateTime::currentMSecsSinceEpoch() > m_highlightEndTimeMsEpoch)
|
||||
{
|
||||
this->stopHighlighting();
|
||||
return;
|
||||
}
|
||||
|
||||
// blink mode, toggle aircraft
|
||||
for (const CSimulatedAircraft &aircraft : as_const(m_highlightedAircraft))
|
||||
{
|
||||
if (m_blinkCycle) { this->callPhysicallyRemoveRemoteAircraft(aircraft.getCallsign(), true); }
|
||||
else { this->callPhysicallyAddRemoteAircraft(aircraft); }
|
||||
}
|
||||
}
|
||||
|
||||
void CSimulatorCommon::resetAircraftFromProvider(const CCallsign &callsign)
|
||||
{
|
||||
const CSimulatedAircraft aircraft(this->getAircraftInRangeForCallsign(callsign));
|
||||
const bool enabled = aircraft.isEnabled();
|
||||
if (enabled)
|
||||
{
|
||||
// are we already visible?
|
||||
if (!this->isPhysicallyRenderedAircraft(callsign))
|
||||
{
|
||||
this->callPhysicallyAddRemoteAircraft(aircraft); // enable/disable
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->callPhysicallyRemoveRemoteAircraft(callsign);
|
||||
}
|
||||
}
|
||||
|
||||
void CSimulatorCommon::clearData(const CCallsign &callsign)
|
||||
{
|
||||
m_highlightedAircraft.removeByCallsign(callsign);
|
||||
m_statsPhysicallyRemovedAircraft++;
|
||||
m_clampedLogMsg.clear();
|
||||
m_lastSentParts.remove(callsign);
|
||||
m_lastSentSituations.remove(callsign);
|
||||
m_clampedLogMsg.remove(callsign);
|
||||
this->removeInterpolationSetupPerCallsign(callsign);
|
||||
}
|
||||
|
||||
void CSimulatorCommon::reloadWeatherSettings()
|
||||
{
|
||||
if (!m_isWeatherActivated) { return; }
|
||||
const auto selectedWeatherScenario = m_weatherScenarioSettings.get();
|
||||
if (!CWeatherScenario::isRealWeatherScenario(selectedWeatherScenario))
|
||||
{
|
||||
m_lastWeatherPosition = {};
|
||||
this->injectWeatherGrid(CWeatherGrid::getByScenario(selectedWeatherScenario));
|
||||
}
|
||||
}
|
||||
|
||||
void CSimulatorCommon::reverseLookupAndUpdateOwnAircraftModel(const QString &modelString)
|
||||
{
|
||||
CAircraftModel model = getOwnAircraftModel();
|
||||
model.setModelString(modelString);
|
||||
this->reverseLookupAndUpdateOwnAircraftModel(model);
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::parseDetails(const CSimpleCommandParser &parser)
|
||||
{
|
||||
Q_UNUSED(parser);
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSimulatorCommon::debugLogMessage(const QString &msg)
|
||||
{
|
||||
if (!this->showDebugLogMessage()) { return; }
|
||||
if (msg.isEmpty()) { return; }
|
||||
const CStatusMessage m = CStatusMessage(this).info("%1") << msg;
|
||||
emit this->driverMessages(m);
|
||||
}
|
||||
|
||||
void CSimulatorCommon::debugLogMessage(const QString &funcInfo, const QString &msg)
|
||||
{
|
||||
if (!this->showDebugLogMessage()) { return; }
|
||||
if (msg.isEmpty()) { return; }
|
||||
const CStatusMessage m = CStatusMessage(this).info("%1 %2") << msg << funcInfo;
|
||||
emit this->driverMessages(m);
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::showDebugLogMessage() const
|
||||
{
|
||||
const bool show = this->getInterpolationSetupGlobal().showSimulatorDebugMessages();
|
||||
return show;
|
||||
}
|
||||
|
||||
void CSimulatorCommon::reverseLookupAndUpdateOwnAircraftModel(const BlackMisc::Simulation::CAircraftModel &model)
|
||||
{
|
||||
Q_ASSERT_X(sApp, Q_FUNC_INFO, "Missing sApp");
|
||||
Q_ASSERT_X(sApp->hasWebDataServices(), Q_FUNC_INFO, "Missing web services");
|
||||
|
||||
if (!model.hasModelString()) { return; }
|
||||
if (this->getOwnAircraftModel() != model)
|
||||
{
|
||||
if (CDatabaseUtils::hasDbAircraftData())
|
||||
{
|
||||
const CAircraftModel newModel = this->reverseLookupModel(model);
|
||||
const bool updated = this->updateOwnModel(newModel); // update in provider (normally the context)
|
||||
if (updated)
|
||||
{
|
||||
emit this->ownAircraftModelChanged(this->getOwnAircraftModel());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we wait for the data
|
||||
connect(sApp->getWebDataServices(), &CWebDataServices::swiftDbModelMatchingEntitiesRead, this, [ = ]
|
||||
{
|
||||
this->reverseLookupAndUpdateOwnAircraftModel(model);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CAirportList CSimulatorCommon::getAirportsInRange() const
|
||||
{
|
||||
// default implementation
|
||||
if (this->isShuttingDown()) { return CAirportList(); }
|
||||
if (!sApp || !sApp->hasWebDataServices()) { return CAirportList(); }
|
||||
|
||||
const CAirportList airports = sApp->getWebDataServices()->getAirports();
|
||||
if (airports.isEmpty()) { return airports; }
|
||||
const CCoordinateGeodetic ownPosition = this->getOwnAircraftPosition();
|
||||
CAirportList airportInRange = airports.findClosest(maxAirportsInRange(), ownPosition);
|
||||
if (m_autoCalcAirportDistance) { airportInRange.calculcateAndUpdateRelativeDistanceAndBearing(ownPosition); }
|
||||
return airportInRange;
|
||||
}
|
||||
|
||||
void CSimulatorCommon::setWeatherActivated(bool activated)
|
||||
{
|
||||
m_isWeatherActivated = activated;
|
||||
if (m_isWeatherActivated)
|
||||
{
|
||||
const auto selectedWeatherScenario = m_weatherScenarioSettings.get();
|
||||
if (!CWeatherScenario::isRealWeatherScenario(selectedWeatherScenario))
|
||||
{
|
||||
m_lastWeatherPosition = {};
|
||||
this->injectWeatherGrid(CWeatherGrid::getByScenario(selectedWeatherScenario));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CAircraftModel CSimulatorCommon::reverseLookupModel(const CAircraftModel &model)
|
||||
{
|
||||
bool modified = false;
|
||||
const CAircraftModel reverseModel = CDatabaseUtils::consolidateOwnAircraftModelWithDbData(model, false, &modified);
|
||||
return reverseModel;
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::isUpdateAircraftLimited(qint64 timestamp)
|
||||
{
|
||||
if (!m_limitUpdateAircraft) { return false; }
|
||||
const bool hasToken = m_limitUpdateAircraftBucket.tryConsume(1, timestamp);
|
||||
return !hasToken;
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::isUpdateAircraftLimitedWithStats(qint64 startTime)
|
||||
{
|
||||
const bool limited = this->isUpdateAircraftLimited(startTime);
|
||||
this->setStatsRemoteAircraftUpdate(startTime, limited);
|
||||
return limited;
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::limitToUpdatesPerSecond(int numberPerSecond)
|
||||
{
|
||||
if (numberPerSecond < 1)
|
||||
{
|
||||
m_limitUpdateAircraft = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
int tokens = 0.1 * numberPerSecond; // 100ms
|
||||
do
|
||||
{
|
||||
if (tokens >= 3) { m_limitUpdateAircraftBucket.setInterval(100); break; }
|
||||
tokens = 0.25 * numberPerSecond; // 250ms
|
||||
if (tokens >= 3) { m_limitUpdateAircraftBucket.setInterval(250); break; }
|
||||
tokens = 0.5 * numberPerSecond; // 500ms
|
||||
if (tokens >= 3) { m_limitUpdateAircraftBucket.setInterval(500); break; }
|
||||
tokens = numberPerSecond;
|
||||
m_limitUpdateAircraftBucket.setInterval(1000);
|
||||
}
|
||||
while (false);
|
||||
|
||||
m_limitUpdateAircraftBucket.setCapacityAndTokensToRefill(tokens);
|
||||
m_limitUpdateAircraft = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
QString CSimulatorCommon::updateAircraftLimitationInfo() const
|
||||
{
|
||||
if (!m_limitUpdateAircraft) { return QStringLiteral("not limited"); }
|
||||
static const QString limInfo("Limited %1 times with %2/secs.");
|
||||
return limInfo.arg(m_statsUpdateAircraftLimited).arg(m_limitUpdateAircraftBucket.getTokensPerSecond());
|
||||
}
|
||||
|
||||
void CSimulatorCommon::resetLastSentValues()
|
||||
{
|
||||
m_lastSentParts.clear();
|
||||
m_lastSentSituations.clear();
|
||||
}
|
||||
|
||||
void CSimulatorCommon::resetLastSentValues(const CCallsign &callsign)
|
||||
{
|
||||
m_lastSentParts.remove(callsign);
|
||||
m_lastSentSituations.remove(callsign);
|
||||
}
|
||||
|
||||
void CSimulatorCommon::onSwiftDbAllDataRead()
|
||||
{
|
||||
// void, can be overridden in specialized drivers
|
||||
}
|
||||
|
||||
void CSimulatorCommon::onSwiftDbModelMatchingEntitiesRead()
|
||||
{
|
||||
// void, can be overridden in specialized drivers
|
||||
}
|
||||
|
||||
void CSimulatorCommon::onSwiftDbAirportsRead()
|
||||
{
|
||||
// void, can be overridden in specialized drivers
|
||||
}
|
||||
|
||||
const CSimulatorInternals &CSimulatorCommon::getSimulatorInternals() const
|
||||
{
|
||||
return m_simulatorInternals;
|
||||
}
|
||||
|
||||
void CSimulatorCommon::unload()
|
||||
{
|
||||
this->disconnectFrom(); // disconnect from simulator
|
||||
m_remoteAircraftProviderConnections.disconnectAll(); // disconnect signals from provider
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::disconnectFrom()
|
||||
{
|
||||
// supposed to be overridden
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::logicallyReAddRemoteAircraft(const CCallsign &callsign)
|
||||
{
|
||||
if (this->isShuttingDown()) { return false; }
|
||||
if (callsign.isEmpty()) { return false; }
|
||||
this->stopHighlighting();
|
||||
this->logicallyRemoveRemoteAircraft(callsign);
|
||||
if (!this->isAircraftInRange(callsign)) { return false; }
|
||||
const QPointer<CSimulatorCommon> myself(this);
|
||||
QTimer::singleShot(2500, this, [ = ]
|
||||
{
|
||||
if (myself.isNull()) { return; }
|
||||
if (this->isShuttingDown()) { return; }
|
||||
if (!this->isAircraftInRange(callsign)) { return; }
|
||||
const CSimulatedAircraft aircraft = this->getAircraftInRangeForCallsign(callsign);
|
||||
if (aircraft.isEnabled() && aircraft.hasModelString())
|
||||
{
|
||||
this->logicallyAddRemoteAircraft(aircraft);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
CCallsignSet CSimulatorCommon::unrenderedEnabledAircraft() const
|
||||
{
|
||||
const CSimulatedAircraftList aircraft = this->getAircraftInRange().findByEnabled(true);
|
||||
if (aircraft.isEmpty()) { return CCallsignSet(); }
|
||||
CCallsignSet enabledOnes = aircraft.getCallsigns();
|
||||
const CCallsignSet renderedOnes = this->physicallyRenderedAircraft();
|
||||
enabledOnes.remove(renderedOnes);
|
||||
return enabledOnes;
|
||||
}
|
||||
|
||||
CCallsignSet CSimulatorCommon::renderedDisabledAircraft() const
|
||||
{
|
||||
const CSimulatedAircraftList aircraft = this->getAircraftInRange().findByEnabled(false);
|
||||
if (aircraft.isEmpty()) { return CCallsignSet(); }
|
||||
const CCallsignSet disabledOnes = aircraft.getCallsigns();
|
||||
const CCallsignSet renderedOnes = this->physicallyRenderedAircraft();
|
||||
return renderedOnes.intersection(disabledOnes);
|
||||
}
|
||||
|
||||
void CSimulatorCommon::highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime)
|
||||
{
|
||||
const CCallsign cs(aircraftToHighlight.getCallsign());
|
||||
m_highlightedAircraft.removeByCallsign(cs);
|
||||
if (enableHighlight)
|
||||
{
|
||||
const qint64 deltaT = displayTime.valueRounded(CTimeUnit::ms(), 0);
|
||||
m_highlightEndTimeMsEpoch = QDateTime::currentMSecsSinceEpoch() + deltaT;
|
||||
m_highlightedAircraft.push_back(aircraftToHighlight);
|
||||
}
|
||||
}
|
||||
|
||||
int CSimulatorCommon::physicallyRemoveMultipleRemoteAircraft(const CCallsignSet &callsigns)
|
||||
{
|
||||
if (callsigns.isEmpty()) { return 0; }
|
||||
this->stopHighlighting();
|
||||
int removed = 0;
|
||||
for (const CCallsign &callsign : callsigns)
|
||||
{
|
||||
this->callPhysicallyRemoveRemoteAircraft(callsign);
|
||||
removed++;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
int CSimulatorCommon::physicallyRemoveAllRemoteAircraft()
|
||||
{
|
||||
// a default implementation, but normally overridden by the sims
|
||||
const CCallsignSet callsigns = this->getAircraftInRangeCallsigns();
|
||||
const int r = this->physicallyRemoveMultipleRemoteAircraft(callsigns);
|
||||
this->debugVerifyStateAfterAllAircraftRemoved();
|
||||
this->clearAllRemoteAircraftData();
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::changeRemoteAircraftEnabled(const CSimulatedAircraft &aircraft)
|
||||
{
|
||||
if (this->isShuttingDown()) { return false; }
|
||||
return aircraft.isEnabled() ?
|
||||
this->physicallyAddRemoteAircraft(aircraft) :
|
||||
this->physicallyRemoveRemoteAircraft(aircraft.getCallsign());
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::changeRemoteAircraftModel(const CSimulatedAircraft &aircraft)
|
||||
{
|
||||
// we expect the new model "in aircraft"
|
||||
// remove upfront, and then enable / disable again
|
||||
if (this->isShuttingDown()) { return false; }
|
||||
const CCallsign callsign = aircraft.getCallsign();
|
||||
if (!this->isPhysicallyRenderedAircraft(callsign)) { return false; }
|
||||
this->physicallyRemoveRemoteAircraft(callsign);
|
||||
return this->changeRemoteAircraftEnabled(aircraft);
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::parseCommandLine(const QString &commandLine, const CIdentifier &originator)
|
||||
{
|
||||
if (this->isMyIdentifier(originator)) { return false; }
|
||||
if (this->isShuttingDown()) { return false; }
|
||||
|
||||
if (commandLine.isEmpty()) { return false; }
|
||||
CSimpleCommandParser parser({ ".plugin", ".drv", ".driver" });
|
||||
parser.parse(commandLine);
|
||||
if (!parser.isKnownCommand()) { return false; }
|
||||
|
||||
// .plugin unload
|
||||
if (parser.matchesPart(1, "unload")) { this->unload(); return true; }
|
||||
|
||||
// .plugin log interpolator
|
||||
const QString part1(parser.part(1).toLower().trimmed());
|
||||
if (part1.startsWith("logint") && parser.hasPart(2))
|
||||
{
|
||||
const QString part2 = parser.part(2).toLower();
|
||||
if (part2 == "off" || part2 == "false")
|
||||
{
|
||||
CStatusMessage(this).info("Disabled interpolation logging");
|
||||
this->clearInterpolationLogCallsigns();
|
||||
return true;
|
||||
}
|
||||
if (part2 == "clear" || part2 == "clr")
|
||||
{
|
||||
m_interpolationLogger.clearLog();
|
||||
CStatusMessage(this).info("Cleared interpolation logging");
|
||||
this->clearInterpolationLogCallsigns();
|
||||
return true;
|
||||
}
|
||||
if (part2.startsWith("max"))
|
||||
{
|
||||
if (!parser.hasPart(3)) { return false; }
|
||||
bool ok;
|
||||
const int max = parser.part(3).toInt(&ok);
|
||||
if (!ok) { return false; }
|
||||
m_interpolationLogger.setMaxSituations(max);
|
||||
CStatusMessage(this).info("Max.situations logged: %1") << max;
|
||||
return true;
|
||||
}
|
||||
if (part2 == "write" || part2 == "save")
|
||||
{
|
||||
// stop logging of other log
|
||||
this->clearInterpolationLogCallsigns();
|
||||
|
||||
// write
|
||||
m_interpolationLogger.writeLogInBackground();
|
||||
CLogMessage(this).info("Started writing interpolation log");
|
||||
return true;
|
||||
}
|
||||
if (part2 == "show")
|
||||
{
|
||||
const QDir dir(CInterpolationLogger::getLogDirectory());
|
||||
if (CDirectoryUtils::isDirExisting(dir))
|
||||
{
|
||||
const QUrl dirUrl = QUrl::fromLocalFile(dir.absolutePath());
|
||||
QDesktopServices::openUrl(dirUrl); // show dir in browser
|
||||
}
|
||||
else
|
||||
{
|
||||
CLogMessage(this).warning("No interpolation log directory");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const CCallsign cs(part2.toUpper());
|
||||
if (!cs.isValid()) { return false; }
|
||||
if (this->getAircraftInRangeCallsigns().contains(cs))
|
||||
{
|
||||
CLogMessage(this).info("Will log interpolation for '%1'") << cs.asString();
|
||||
this->setLogCallsign(true, cs);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLogMessage(this).warning("Cannot log interpolation for '%1', no aircraft in range") << cs.asString();
|
||||
return false;
|
||||
}
|
||||
} // logint
|
||||
|
||||
if (part1.startsWith("spline") || part1.startsWith("linear"))
|
||||
{
|
||||
if (parser.hasPart(2))
|
||||
{
|
||||
const CCallsign cs(parser.part(2));
|
||||
const bool changed = this->setInterpolationMode(part1, cs);
|
||||
CLogMessage(this).info(changed ? "Changed interpolation mode for '%1'" : "Unchanged interpolation mode for '%1'") << cs.asString();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CInterpolationAndRenderingSetupGlobal setup = this->getInterpolationSetupGlobal();
|
||||
const bool changed = setup.setInterpolatorMode(part1);
|
||||
if (changed) { this->setInterpolationSetupGlobal(setup); }
|
||||
CLogMessage(this).info(changed ? "Changed interpolation mode globally" : "Unchanged interpolation mode");
|
||||
return true;
|
||||
}
|
||||
} // spline/linear
|
||||
|
||||
if (part1.startsWith("pos"))
|
||||
{
|
||||
CCallsign cs(parser.part(2).toUpper());
|
||||
if (!cs.isValid())
|
||||
{
|
||||
const CCallsignSet csSet = this->getLogCallsigns();
|
||||
if (csSet.size() != 1) { return false; }
|
||||
|
||||
// if there is just one we take that one
|
||||
cs = *csSet.begin();
|
||||
}
|
||||
|
||||
this->setLogCallsign(true, cs);
|
||||
CLogMessage(this).info("Display position for '%1'") << cs.asString();
|
||||
this->displayLoggedSituationInSimulator(cs, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parser.hasPart(2) && (part1.startsWith("aircraft") || part1.startsWith("ac")))
|
||||
{
|
||||
const QString part2 = parser.part(2).toLower();
|
||||
if (parser.hasPart(3) && (part2.startsWith("readd") || part2.startsWith("re-add")))
|
||||
{
|
||||
const QString cs = parser.part(3).toUpper();
|
||||
if (cs == "all")
|
||||
{
|
||||
this->physicallyRemoveAllRemoteAircraft();
|
||||
const CStatusMessageList msgs = this->debugVerifyStateAfterAllAircraftRemoved();
|
||||
this->clearAllRemoteAircraftData();
|
||||
if (!msgs.isEmpty()) { emit this->driverMessages(msgs); }
|
||||
const CSimulatedAircraftList aircraft = this->getAircraftInRange();
|
||||
for (const CSimulatedAircraft a : aircraft)
|
||||
{
|
||||
if (a.isEnabled()) { this->logicallyAddRemoteAircraft(a); }
|
||||
}
|
||||
}
|
||||
else if (CCallsign::isValidAircraftCallsign(cs))
|
||||
{
|
||||
this->logicallyReAddRemoteAircraft(cs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (parser.hasPart(3) && (part2.startsWith("rm") || part2.startsWith("remove")))
|
||||
{
|
||||
const QString cs = parser.part(3).toUpper();
|
||||
if (CCallsign::isValidAircraftCallsign(cs))
|
||||
{
|
||||
this->logicallyRemoveRemoteAircraft(cs);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (part1.startsWith("limit"))
|
||||
{
|
||||
const int perSecond = parser.toInt(2, -1);
|
||||
this->limitToUpdatesPerSecond(perSecond);
|
||||
CLogMessage(this).info("Remote aircraft updates limitations: %1") << this->updateAircraftLimitationInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
// driver specific cmd line arguments
|
||||
return this->parseDetails(parser);
|
||||
}
|
||||
|
||||
void CSimulatorCommon::registerHelp()
|
||||
{
|
||||
if (CSimpleCommandParser::registered("BlackCore::CSimulatorCommon")) { return; }
|
||||
CSimpleCommandParser::registerCommand({".drv", "alias: .driver .plugin"});
|
||||
CSimpleCommandParser::registerCommand({".drv limit number/secs.", "limit updates to number per second (0..off)"});
|
||||
CSimpleCommandParser::registerCommand({".drv logint callsign", "log interpolator for callsign"});
|
||||
CSimpleCommandParser::registerCommand({".drv logint off", "no log information for interpolator"});
|
||||
CSimpleCommandParser::registerCommand({".drv logint write", "write interpolator log to file"});
|
||||
CSimpleCommandParser::registerCommand({".drv logint clear", "clear current log"});
|
||||
CSimpleCommandParser::registerCommand({".drv logint max number", "max. number of entries logged"});
|
||||
CSimpleCommandParser::registerCommand({".drv pos callsign", "show position for callsign"});
|
||||
CSimpleCommandParser::registerCommand({".drv spline|linear callsign", "set spline/linear interpolator for one/all callsign(s)"});
|
||||
CSimpleCommandParser::registerCommand({".drv aircraft readd callsign", "add again (re-add) a given callsign"});
|
||||
CSimpleCommandParser::registerCommand({".drv aircraft readd all", "add again (re-add) all aircraft"});
|
||||
CSimpleCommandParser::registerCommand({".drv aircraft rm callsign", "remove a given callsign"});
|
||||
}
|
||||
|
||||
void CSimulatorCommon::resetAircraftStatistics()
|
||||
{
|
||||
m_statsUpdateAircraftRuns = 0;
|
||||
m_statsUpdateAircraftTimeAvgMs = 0;
|
||||
m_statsUpdateAircraftTimeTotalMs = 0;
|
||||
m_statsMaxUpdateTimeMs = 0;
|
||||
m_statsCurrentUpdateTimeMs = 0;
|
||||
m_statsPhysicallyAddedAircraft = 0;
|
||||
m_statsPhysicallyRemovedAircraft = 0;
|
||||
m_statsLastUpdateAircraftRequestedMs = 0;
|
||||
m_statsUpdateAircraftRequestedDeltaMs = 0;
|
||||
m_statsUpdateAircraftLimited = 0;
|
||||
ISimulationEnvironmentProvider::resetSimulationEnvironmentStatistics();
|
||||
}
|
||||
|
||||
CStatusMessageList CSimulatorCommon::debugVerifyStateAfterAllAircraftRemoved() const
|
||||
{
|
||||
CStatusMessageList msgs;
|
||||
if (!CBuildConfig::isLocalDeveloperDebugBuild()) { return msgs; }
|
||||
if (!m_addAgainAircraftWhenRemoved.isEmpty()) { msgs.push_back(CStatusMessage(this).error("m_addAgainAircraftWhenRemoved not empty: '%1'") << m_addAgainAircraftWhenRemoved.getCallsignStrings(true).join(", ")); }
|
||||
return msgs;
|
||||
}
|
||||
|
||||
void CSimulatorCommon::oneSecondTimerTimeout()
|
||||
{
|
||||
this->blinkHighlightedAircraft();
|
||||
}
|
||||
|
||||
void CSimulatorCommon::safeKillTimer()
|
||||
{
|
||||
if (m_timerId < 0) { return; }
|
||||
this->killTimer(m_timerId);
|
||||
m_timerId = -1;
|
||||
}
|
||||
|
||||
QString CSimulatorCommon::getInvalidSituationLogMessage(const CCallsign &callsign, const CInterpolationStatus &status, const QString &details) const
|
||||
{
|
||||
static const QString msg("CS: '%1' Interpolation: '%2'");
|
||||
const QString m = msg.arg(callsign.asString(), status.toQString());
|
||||
if (details.isEmpty()) { return m; }
|
||||
|
||||
static const QString addDetails(" details: '%1'");
|
||||
return m + addDetails.arg(details);
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::clampedLog(const CCallsign &callsign, const CStatusMessage &message)
|
||||
{
|
||||
if (message.isEmpty()) { return false; }
|
||||
constexpr qint64 Timeout = 2000;
|
||||
const qint64 clampTs = m_clampedLogMsg.value(callsign, -1);
|
||||
const qint64 ts = QDateTime::currentMSecsSinceEpoch();
|
||||
if (clampTs > 0 && ((clampTs + Timeout) > ts)) { return false; }
|
||||
CLogMessage::preformatted(message);
|
||||
m_clampedLogMsg[callsign] = ts;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSimulatorCommon::removedClampedLog(const CCallsign &callsign)
|
||||
{
|
||||
m_clampedLogMsg.remove(callsign);
|
||||
}
|
||||
|
||||
void CSimulatorCommon::setStatsRemoteAircraftUpdate(qint64 startTime, bool limited)
|
||||
{
|
||||
const qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
const qint64 dt = now - startTime;
|
||||
m_statsCurrentUpdateTimeMs = dt;
|
||||
m_statsUpdateAircraftTimeTotalMs += dt;
|
||||
m_statsUpdateAircraftRuns++;
|
||||
m_statsUpdateAircraftTimeAvgMs = static_cast<double>(m_statsUpdateAircraftTimeTotalMs) / static_cast<double>(m_statsUpdateAircraftRuns);
|
||||
m_updateRemoteAircraftInProgress = false;
|
||||
m_statsLastUpdateAircraftRequestedMs = startTime;
|
||||
|
||||
if (m_statsMaxUpdateTimeMs < dt) { m_statsMaxUpdateTimeMs = dt; }
|
||||
if (m_statsLastUpdateAircraftRequestedMs > 0) { m_statsUpdateAircraftRequestedDeltaMs = startTime - m_statsLastUpdateAircraftRequestedMs; }
|
||||
if (limited) { m_statsUpdateAircraftLimited++; }
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::isEqualLastSent(const CAircraftSituation &compare) const
|
||||
{
|
||||
Q_ASSERT_X(compare.hasCallsign(), Q_FUNC_INFO, "Need callsign");
|
||||
if (!m_lastSentSituations.contains(compare.getCallsign())) { return false; }
|
||||
if (compare.isNull()) { return false; }
|
||||
return compare.equalPbhVectorAltitude(m_lastSentSituations.value(compare.getCallsign()));
|
||||
}
|
||||
|
||||
bool CSimulatorCommon::isEqualLastSent(const CAircraftParts &compare, const CCallsign &callsign) const
|
||||
{
|
||||
if (callsign.isEmpty()) { return false; }
|
||||
if (!m_lastSentParts.contains(callsign)) { return false; }
|
||||
return compare.equalValues(m_lastSentParts.value(callsign));
|
||||
}
|
||||
|
||||
void CSimulatorCommon::rememberLastSent(const CAircraftSituation &sent)
|
||||
{
|
||||
Q_ASSERT_X(sent.hasCallsign(), Q_FUNC_INFO, "Need callsign");
|
||||
m_lastSentSituations.insert(sent.getCallsign(), sent);
|
||||
}
|
||||
|
||||
void CSimulatorCommon::rememberLastSent(const CAircraftParts &sent, const CCallsign &callsign)
|
||||
{
|
||||
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Need callsign");
|
||||
m_lastSentParts.insert(callsign, sent);
|
||||
}
|
||||
|
||||
CAircraftSituationList CSimulatorCommon::getLastSentCanLikelySkipNearGroundInterpolation() const
|
||||
{
|
||||
const QList<CAircraftSituation> situations = m_lastSentSituations.values();
|
||||
CAircraftSituationList skipped;
|
||||
for (const CAircraftSituation &s : situations)
|
||||
{
|
||||
if (s.canLikelySkipNearGroundInterpolation()) { skipped.push_back(s); }
|
||||
}
|
||||
return skipped;
|
||||
}
|
||||
|
||||
void CSimulatorCommon::onRecalculatedRenderedAircraft(const CAirspaceAircraftSnapshot &snapshot)
|
||||
{
|
||||
if (!snapshot.isValidSnapshot()) { return;}
|
||||
|
||||
// for unrestricted values all add/remove actions are directly linked
|
||||
// when changing back from restricted->unrestricted an one time update is required
|
||||
if (!snapshot.isRestricted() && !snapshot.isRestrictionChanged()) { return; }
|
||||
|
||||
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "Needs to run in object thread");
|
||||
Q_ASSERT_X(snapshot.generatingThreadName() != QThread::currentThread()->objectName(), Q_FUNC_INFO, "Expect snapshot from background thread");
|
||||
|
||||
// restricted snapshot values?
|
||||
bool changed = false;
|
||||
if (snapshot.isRenderingEnabled())
|
||||
{
|
||||
const CCallsignSet callsignsInSimulator(this->physicallyRenderedAircraft()); // state in simulator
|
||||
const CCallsignSet callsignsToBeRemoved(callsignsInSimulator.difference(snapshot.getEnabledAircraftCallsignsByDistance()));
|
||||
const CCallsignSet callsignsToBeAdded(snapshot.getEnabledAircraftCallsignsByDistance().difference(callsignsInSimulator));
|
||||
if (!callsignsToBeRemoved.isEmpty())
|
||||
{
|
||||
const int r = this->physicallyRemoveMultipleRemoteAircraft(callsignsToBeRemoved);
|
||||
changed = r > 0;
|
||||
}
|
||||
|
||||
if (!callsignsToBeAdded.isEmpty())
|
||||
{
|
||||
CSimulatedAircraftList aircraftToBeAdded(this->getAircraftInRange().findByCallsigns(callsignsToBeAdded)); // thread safe copy
|
||||
for (const CSimulatedAircraft &aircraft : aircraftToBeAdded)
|
||||
{
|
||||
Q_ASSERT_X(aircraft.isEnabled(), Q_FUNC_INFO, "Disabled aircraft detected as to be added");
|
||||
Q_ASSERT_X(aircraft.hasModelString(), Q_FUNC_INFO, "Missing model string");
|
||||
this->callPhysicallyAddRemoteAircraft(aircraft); // recalcuate snapshot
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no rendering at all, we remove everything
|
||||
const int r = this->physicallyRemoveAllRemoteAircraft();
|
||||
changed = r > 0;
|
||||
}
|
||||
|
||||
// we have handled snapshot
|
||||
if (changed)
|
||||
{
|
||||
emit this->airspaceSnapshotHandled();
|
||||
}
|
||||
}
|
||||
|
||||
void CSimulatorCommon::reset()
|
||||
{
|
||||
this->clearAllRemoteAircraftData();
|
||||
}
|
||||
|
||||
void CSimulatorCommon::resetHighlighting()
|
||||
{
|
||||
m_highlightedAircraft.clear();
|
||||
m_blinkCycle = false;
|
||||
m_highlightEndTimeMsEpoch = false;
|
||||
}
|
||||
|
||||
void CSimulatorCommon::stopHighlighting()
|
||||
{
|
||||
// restore
|
||||
const CSimulatedAircraftList highlightedAircraft(m_highlightedAircraft);
|
||||
for (const CSimulatedAircraft &aircraft : highlightedAircraft)
|
||||
{
|
||||
// get the current state for this aircraft
|
||||
// it might has been removed in the meantime
|
||||
const CCallsign cs(aircraft.getCallsign());
|
||||
this->resetAircraftFromProvider(cs);
|
||||
}
|
||||
this->resetHighlighting();
|
||||
}
|
||||
|
||||
void CSimulatorCommon::clearAllRemoteAircraftData()
|
||||
{
|
||||
// rendering related stuff
|
||||
m_addAgainAircraftWhenRemoved.clear();
|
||||
m_callsignsToBeRendered.clear();
|
||||
m_clampedLogMsg.clear();
|
||||
m_lastSentParts.clear();
|
||||
m_lastSentSituations.clear();
|
||||
m_updateRemoteAircraftInProgress = false;
|
||||
|
||||
this->clearInterpolationSetupsPerCallsign();
|
||||
this->resetHighlighting();
|
||||
this->resetAircraftStatistics();
|
||||
}
|
||||
|
||||
CAirportList CSimulatorCommon::getWebServiceAirports() const
|
||||
{
|
||||
if (this->isShuttingDown()) { return CAirportList(); }
|
||||
if (!sApp->hasWebDataServices()) { return CAirportList(); }
|
||||
return sApp->getWebDataServices()->getAirports();
|
||||
}
|
||||
|
||||
CAirport CSimulatorCommon::getWebServiceAirport(const CAirportIcaoCode &icao) const
|
||||
{
|
||||
if (this->isShuttingDown()) { return CAirport(); }
|
||||
if (!sApp->hasWebDataServices()) { return CAirport(); }
|
||||
return sApp->getWebDataServices()->getAirports().findFirstByIcao(icao);
|
||||
}
|
||||
|
||||
void CSimulatorCommon::rapOnRecalculatedRenderedAircraft(const CAirspaceAircraftSnapshot &snapshot)
|
||||
{
|
||||
if (!this->isConnected()) { return; }
|
||||
if (this->isShuttingDown()) { return; }
|
||||
this->onRecalculatedRenderedAircraft(snapshot);
|
||||
}
|
||||
|
||||
void CSimulatorCommon::rapOnRemoteProviderRemovedAircraft(const CCallsign &callsign)
|
||||
{
|
||||
Q_UNUSED(callsign);
|
||||
// currently not used, the calls are handled by context call logicallyRemoveRemoteAircraft
|
||||
}
|
||||
|
||||
void CSimulatorCommon::callPhysicallyAddRemoteAircraft(const CSimulatedAircraft &remoteAircraft)
|
||||
{
|
||||
m_statsPhysicallyAddedAircraft++;
|
||||
this->physicallyAddRemoteAircraft(remoteAircraft);
|
||||
}
|
||||
|
||||
void CSimulatorCommon::callPhysicallyRemoveRemoteAircraft(const CCallsign &remoteCallsign, bool blinking)
|
||||
{
|
||||
if (!blinking) { this->clearData(remoteCallsign); }
|
||||
this->physicallyRemoveRemoteAircraft(remoteCallsign);
|
||||
}
|
||||
|
||||
QString CSimulatorCommon::latestLoggedDataFormatted(const CCallsign &cs) const
|
||||
{
|
||||
const SituationLog s = m_interpolationLogger.getLastSituationLog(cs);
|
||||
const PartsLog p = m_interpolationLogger.getLastPartsLog(cs);
|
||||
|
||||
static const QString sep("\n------\n");
|
||||
QString dm;
|
||||
if (s.tsCurrent > 0)
|
||||
{
|
||||
dm = QStringLiteral("Setup: ") % s.usedSetup.toQString(true) %
|
||||
QStringLiteral("\n\n") %
|
||||
QStringLiteral("Situation: ") % s.toQString(false, true, true, true, true, sep);
|
||||
}
|
||||
if (p.tsCurrent > 0) { dm += (dm.isEmpty() ? QStringLiteral("") : QStringLiteral("\n\n")) % QStringLiteral("Parts: ") % p.toQString(sep); }
|
||||
return dm;
|
||||
}
|
||||
|
||||
void CSimulatorCommon::displayLoggedSituationInSimulator(const CCallsign &cs, bool stopLogging, int times)
|
||||
{
|
||||
if (cs.isEmpty()) { return; }
|
||||
if (this->isShuttingDown()) { return; }
|
||||
const CInterpolationAndRenderingSetupPerCallsign setup = this->getInterpolationSetupPerCallsignOrDefault(cs);
|
||||
const bool logsCs = setup.logInterpolation();
|
||||
if (!logsCs) { return; }
|
||||
|
||||
stopLogging = stopLogging || !this->isSimulating(); // stop when sim was stopped
|
||||
stopLogging = stopLogging && logsCs;
|
||||
if (!stopLogging && times < 1) { return; }
|
||||
|
||||
const bool inRange = this->getAircraftInRangeCallsigns().contains(cs);
|
||||
if (!stopLogging && !inRange) { return; }
|
||||
if (stopLogging && (times < 1 || !inRange))
|
||||
{
|
||||
this->setLogCallsign(false, cs);
|
||||
return;
|
||||
}
|
||||
|
||||
const QString dm = this->latestLoggedDataFormatted(cs);
|
||||
if (!dm.isEmpty())
|
||||
{
|
||||
this->displayStatusMessage(CStatusMessage(this).info(dm));
|
||||
emit this->requestUiConsoleMessage(dm, true);
|
||||
}
|
||||
|
||||
const int t = 4500 + (qrand() % 1000); // makes sure not always using the same time difference
|
||||
const QPointer<CSimulatorCommon> myself(this);
|
||||
QTimer::singleShot(t, this, [ = ]
|
||||
{
|
||||
if (myself.isNull() || myself->isShuttingDown()) { return; }
|
||||
this->displayLoggedSituationInSimulator(cs, stopLogging, times - 1);
|
||||
});
|
||||
}
|
||||
} // namespace
|
||||
@@ -1,345 +0,0 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKCORE_SIMULATOR_COMMON_H
|
||||
#define BLACKCORE_SIMULATOR_COMMON_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QReadWriteLock>
|
||||
#include <QtGlobal>
|
||||
#include <QMap>
|
||||
|
||||
#include "blackcore/aircraftmatcher.h"
|
||||
#include "blackcore/blackcoreexport.h"
|
||||
#include "blackcore/simulator.h"
|
||||
#include "blackmisc/simulation/aircraftmodelsetloader.h"
|
||||
#include "blackmisc/simulation/simulatedaircraftlist.h"
|
||||
#include "blackmisc/simulation/simulatorinfo.h"
|
||||
#include "blackmisc/simulation/simulatorplugininfo.h"
|
||||
#include "blackmisc/simulation/simulatorinternals.h"
|
||||
#include "blackmisc/simulation/settings/simulatorsettings.h"
|
||||
#include "blackmisc/simulation/interpolationrenderingsetup.h"
|
||||
#include "blackmisc/simulation/interpolationlogger.h"
|
||||
#include "blackmisc/aviation/callsignset.h"
|
||||
#include "blackmisc/pq/length.h"
|
||||
#include "blackmisc/pq/time.h"
|
||||
#include "blackmisc/pq/units.h"
|
||||
#include "blackmisc/tokenbucket.h"
|
||||
#include "blackmisc/connectionguard.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CSimpleCommandParser;
|
||||
|
||||
namespace Aviation
|
||||
{
|
||||
class CAircraftParts;
|
||||
class CAircraftSituation;
|
||||
class CCallsign;
|
||||
}
|
||||
namespace Simulation
|
||||
{
|
||||
class CAirspaceAircraftSnapshot;
|
||||
class CSimulatedAircraft;
|
||||
}
|
||||
}
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
//! Common base class with providers, interface and some base functionality
|
||||
class BLACKCORE_EXPORT CSimulatorCommon : public ISimulator
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(BlackCore::ISimulator)
|
||||
Q_INTERFACES(BlackMisc::Simulation::ISimulationEnvironmentProvider)
|
||||
Q_INTERFACES(BlackMisc::Simulation::IInterpolationSetupProvider)
|
||||
|
||||
public:
|
||||
//! Log categories
|
||||
static const BlackMisc::CLogCategoryList &getLogCategories();
|
||||
|
||||
//! Destructor
|
||||
virtual ~CSimulatorCommon();
|
||||
|
||||
// --------- ISimulator implementations ------------
|
||||
virtual void highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime) override;
|
||||
virtual const BlackMisc::Simulation::CSimulatorInternals &getSimulatorInternals() const override;
|
||||
virtual BlackMisc::Aviation::CAirportList getAirportsInRange() const override;
|
||||
virtual void setWeatherActivated(bool activated) override;
|
||||
virtual void unload() override;
|
||||
virtual bool disconnectFrom() override;
|
||||
virtual bool logicallyReAddRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override;
|
||||
virtual BlackMisc::Aviation::CCallsignSet unrenderedEnabledAircraft() const override;
|
||||
virtual BlackMisc::Aviation::CCallsignSet renderedDisabledAircraft() const override;
|
||||
virtual int physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns) override;
|
||||
virtual int physicallyRemoveAllRemoteAircraft() override;
|
||||
virtual bool changeRemoteAircraftEnabled(const BlackMisc::Simulation::CSimulatedAircraft &aircraft) override;
|
||||
virtual bool changeRemoteAircraftModel(const BlackMisc::Simulation::CSimulatedAircraft &aircraft) override;
|
||||
virtual void clearAllRemoteAircraftData() override;
|
||||
virtual void resetAircraftStatistics() override;
|
||||
virtual BlackMisc::CStatusMessageList debugVerifyStateAfterAllAircraftRemoved() const override;
|
||||
|
||||
//! \addtogroup swiftdotcommands
|
||||
//! @{
|
||||
//! <pre>
|
||||
//! .drv unload unload plugin BlackCore::CSimulatorCommon
|
||||
//! .drv limit number limit the number of updates BlackCore::CSimulatorCommon
|
||||
//! .drv logint callsign log interpolator for callsign BlackCore::CSimulatorCommon
|
||||
//! .drv logint off no log information for interpolator BlackCore::CSimulatorCommon
|
||||
//! .drv logint write write interpolator log to file BlackCore::CSimulatorCommon
|
||||
//! .drv logint clear clear current log BlackCore::CSimulatorCommon
|
||||
//! .drv pos callsign shows current position in simulator BlackCore::CSimulatorCommon
|
||||
//! .drv spline|linear callsign interpolator spline or linear BlackCore::CSimulatorCommon
|
||||
//! .drv aircraft readd callsign re-add (add again) aircraft BlackCore::CSimulatorCommon
|
||||
//! .drv aircraft readd all re-add all aircraft BlackCore::CSimulatorCommon
|
||||
//! .drv aircraft rm callsign remove aircraft BlackCore::CSimulatorCommon
|
||||
//! </pre>
|
||||
//! @}
|
||||
//! \copydoc ISimulator::parseCommandLine
|
||||
virtual bool parseCommandLine(const QString &commandLine, const BlackMisc::CIdentifier &originator) override;
|
||||
|
||||
//! \name Interface implementations, called from context
|
||||
//! @{
|
||||
virtual bool logicallyAddRemoteAircraft(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft) override;
|
||||
virtual bool logicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override;
|
||||
//! @}
|
||||
|
||||
// --------- ISimulator implementations ------------
|
||||
|
||||
//! Register help
|
||||
static void registerHelp();
|
||||
|
||||
//! Counter added aircraft
|
||||
int getStatisticsPhysicallyAddedAircraft() const { return m_statsPhysicallyAddedAircraft; }
|
||||
|
||||
//! Counter removed aircraft
|
||||
int getStatisticsPhysicallyRemovedAircraft() const { return m_statsPhysicallyRemovedAircraft; }
|
||||
|
||||
//! Current update time in ms
|
||||
double getStatisticsCurrentUpdateTimeMs() const { return m_statsCurrentUpdateTimeMs; }
|
||||
|
||||
//! Average update time in ms
|
||||
double getStatisticsAverageUpdateTimeMs() const { return m_statsUpdateAircraftTimeAvgMs; }
|
||||
|
||||
//! Total update time in ms
|
||||
qint64 getStatisticsTotalUpdateTimeMs() const { return m_statsUpdateAircraftTimeTotalMs; }
|
||||
|
||||
//! Max.update time in ms
|
||||
qint64 getStatisticsMaxUpdateTimeMs() const { return m_statsMaxUpdateTimeMs; }
|
||||
|
||||
//! Number of update runs
|
||||
int getStatisticsUpdateRuns() const { return m_statsUpdateAircraftRuns; }
|
||||
|
||||
//! Time between two update requests
|
||||
qint64 getStatisticsAircraftUpdatedRequestedDeltaMs() const { return m_statsUpdateAircraftRequestedDeltaMs; }
|
||||
|
||||
//! Access to logger
|
||||
const BlackMisc::Simulation::CInterpolationLogger &interpolationLogger() const { return m_interpolationLogger; }
|
||||
|
||||
//! The latest logged data formatted
|
||||
//! \remark public only for log. displays
|
||||
QString latestLoggedDataFormatted(const BlackMisc::Aviation::CCallsign &cs) const;
|
||||
|
||||
//! Info about update aircraft limitations
|
||||
QString updateAircraftLimitationInfo() const;
|
||||
|
||||
//! Reset the last sent values
|
||||
void resetLastSentValues();
|
||||
|
||||
//! Reset the last sent values per callsign
|
||||
void resetLastSentValues(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
protected:
|
||||
//! Constructor
|
||||
CSimulatorCommon(const BlackMisc::Simulation::CSimulatorPluginInfo &info,
|
||||
BlackMisc::Simulation::IOwnAircraftProvider *ownAircraftProvider,
|
||||
BlackMisc::Simulation::IRemoteAircraftProvider *remoteAircraftProvider,
|
||||
BlackMisc::Weather::IWeatherGridProvider *weatherGridProvider,
|
||||
BlackMisc::Network::IClientProvider *clientProvider,
|
||||
QObject *parent);
|
||||
|
||||
//! \name When swift DB data are read
|
||||
//! @{
|
||||
virtual void onSwiftDbAllDataRead();
|
||||
virtual void onSwiftDbModelMatchingEntitiesRead();
|
||||
virtual void onSwiftDbAirportsRead();
|
||||
//! @}
|
||||
|
||||
//! \name Connected with remote aircraft provider signals
|
||||
//! @{
|
||||
//! Recalculate the rendered aircraft, this happens when restrictions are applied (max. aircraft, range)
|
||||
virtual void onRecalculatedRenderedAircraft(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &snapshot);
|
||||
//! @}
|
||||
|
||||
//! Max.airports in range
|
||||
int maxAirportsInRange() const;
|
||||
|
||||
//! Full reset of state
|
||||
//! \remark reset as it was unloaded without unloading
|
||||
//! \sa ISimulator::clearAllRemoteAircraftData
|
||||
virtual void reset();
|
||||
|
||||
//! Reset highlighting
|
||||
void resetHighlighting();
|
||||
|
||||
//! Restore all highlighted aircraft
|
||||
void stopHighlighting();
|
||||
|
||||
//! Inject weather grid to simulator
|
||||
virtual void injectWeatherGrid(const BlackMisc::Weather::CWeatherGrid &weatherGrid) { Q_UNUSED(weatherGrid); }
|
||||
|
||||
//! Airports from web services
|
||||
BlackMisc::Aviation::CAirportList getWebServiceAirports() const;
|
||||
|
||||
//! Airport from web services by ICAO code
|
||||
BlackMisc::Aviation::CAirport getWebServiceAirport(const BlackMisc::Aviation::CAirportIcaoCode &icao) const;
|
||||
|
||||
//! Blink the highlighted aircraft
|
||||
void blinkHighlightedAircraft();
|
||||
|
||||
//! Restore aircraft from the provider data
|
||||
void resetAircraftFromProvider(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Clear the related data as statistics etc.
|
||||
virtual void clearData(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Set own model
|
||||
void reverseLookupAndUpdateOwnAircraftModel(const BlackMisc::Simulation::CAircraftModel &model);
|
||||
|
||||
//! Set own model
|
||||
void reverseLookupAndUpdateOwnAircraftModel(const QString &modelString);
|
||||
|
||||
//! Reload weather settings
|
||||
void reloadWeatherSettings();
|
||||
|
||||
//! Parse driver specific details for ISimulator::parseCommandLine
|
||||
virtual bool parseDetails(const BlackMisc::CSimpleCommandParser &parser);
|
||||
|
||||
//! Display a debug log message based on BlackMisc::Simulation::CInterpolationAndRenderingSetup
|
||||
//! remark shows log messages of functions calls
|
||||
void debugLogMessage(const QString &msg);
|
||||
|
||||
//! Display a debug log message based on BlackMisc::Simulation::CInterpolationAndRenderingSetup
|
||||
//! remark shows log messages of functions calls
|
||||
void debugLogMessage(const QString &funcInfo, const QString &msg);
|
||||
|
||||
//! Show log messages?
|
||||
bool showDebugLogMessage() const;
|
||||
|
||||
//! Slow timer used to highlight aircraft, can be used for other things too
|
||||
virtual void oneSecondTimerTimeout();
|
||||
|
||||
//! Kill timer if id is valid
|
||||
void safeKillTimer();
|
||||
|
||||
//! Info about invalid situation
|
||||
QString getInvalidSituationLogMessage(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Simulation::CInterpolationStatus &status, const QString &details = {}) const;
|
||||
|
||||
//! Can a new log message be generated without generating a "message" overflow
|
||||
//! \remark works per callsign
|
||||
//! \remark use this function when there is a risk that a lot of log. messages will be generated in a short time
|
||||
bool clampedLog(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::CStatusMessage &message);
|
||||
|
||||
//! Mark as justed logged
|
||||
//! \remark touch, but also return if it can be logged
|
||||
//! \remark use this function when there is a risk that a lot of log. messages will be generated in a short time
|
||||
void removedClampedLog(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Update stats and flags
|
||||
void setStatsRemoteAircraftUpdate(qint64 startTime, bool limited = false);
|
||||
|
||||
//! Equal to last sent situation
|
||||
bool isEqualLastSent(const BlackMisc::Aviation::CAircraftSituation &compare) const;
|
||||
|
||||
//! Equal to last sent situation
|
||||
bool isEqualLastSent(const BlackMisc::Aviation::CAircraftParts &compare, const BlackMisc::Aviation::CCallsign &callsign) const;
|
||||
|
||||
//! Remember as last sent
|
||||
void rememberLastSent(const BlackMisc::Aviation::CAircraftSituation &sent);
|
||||
|
||||
//! Remember as last sent
|
||||
void rememberLastSent(const BlackMisc::Aviation::CAircraftParts &sent, const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Last sent situations
|
||||
BlackMisc::Aviation::CAircraftSituationList getLastSentCanLikelySkipNearGroundInterpolation() const;
|
||||
|
||||
//! Lookup against DB data
|
||||
static BlackMisc::Simulation::CAircraftModel reverseLookupModel(const BlackMisc::Simulation::CAircraftModel &model);
|
||||
|
||||
bool m_pausedSimFreezesInterpolation = false; //!< paused simulator will also pause interpolation (so AI aircraft will hold)
|
||||
bool m_autoCalcAirportDistance = true; //!< automatically calculate airport distance and bearing
|
||||
bool m_updateRemoteAircraftInProgress = false; //!< currently updating remote aircraft
|
||||
int m_timerId = -1; //!< dispatch timer id
|
||||
int m_statsUpdateAircraftRuns = 0; //!< statistics update count
|
||||
int m_statsUpdateAircraftLimited = 0; //!< skipped because of max.update limitations
|
||||
double m_statsUpdateAircraftTimeAvgMs = 0; //!< statistics average update time
|
||||
qint64 m_statsUpdateAircraftTimeTotalMs = 0; //!< statistics total update time
|
||||
qint64 m_statsCurrentUpdateTimeMs = 0; //!< statistics current update time
|
||||
qint64 m_statsMaxUpdateTimeMs = 0; //!< statistics max.update time
|
||||
qint64 m_statsLastUpdateAircraftRequestedMs = 0; //!< when was the last aircraft update requested
|
||||
qint64 m_statsUpdateAircraftRequestedDeltaMs = 0; //!< delta time between 2 aircraft updates
|
||||
|
||||
BlackMisc::Simulation::CSimulatorInternals m_simulatorInternals; //!< setup object
|
||||
BlackMisc::Simulation::CInterpolationLogger m_interpolationLogger; //!< log.interpolation
|
||||
BlackMisc::Aviation::CTimestampPerCallsign m_clampedLogMsg; //!< when logged last for this callsign, can be used so there is no log message overflow
|
||||
BlackMisc::Aviation::CAircraftSituationPerCallsign m_lastSentSituations; //!< last situation sent to simulator
|
||||
BlackMisc::Aviation::CAircraftPartsPerCallsign m_lastSentParts; //!< last parts sent to simulator
|
||||
|
||||
// some optional functionality which can be used by the simulators as needed
|
||||
BlackMisc::Simulation::CSimulatedAircraftList m_addAgainAircraftWhenRemoved; //!< add this model again when removed, normally used to change model
|
||||
|
||||
// limit the update aircraft to a maximum per second
|
||||
BlackMisc::CTokenBucket m_limitUpdateAircraftBucket { 5, 100, 5 }; //!< means 50 per second
|
||||
bool m_limitUpdateAircraft = false; //!< limit the update frequency by using BlackMisc::CTokenBucket
|
||||
|
||||
//! Limit reached (max number of updates by token bucket if enabled)
|
||||
bool isUpdateAircraftLimited(qint64 timestamp = -1);
|
||||
|
||||
//! Limited as CSimulatorCommon::isUpdateAircraftLimited plus updating statistics
|
||||
bool isUpdateAircraftLimitedWithStats(qint64 startTime = -1);
|
||||
|
||||
//! Limit to updates per second
|
||||
bool limitToUpdatesPerSecond(int numberPerSecond);
|
||||
|
||||
// weather
|
||||
bool m_isWeatherActivated = false; //!< Is simulator weather activated?
|
||||
BlackMisc::Geo::CCoordinateGeodetic m_lastWeatherPosition; //!< Own aircraft position at which weather was fetched and injected last
|
||||
BlackMisc::CSetting<BlackMisc::Simulation::Settings::TSelectedWeatherScenario> m_weatherScenarioSettings { this, &CSimulatorCommon::reloadWeatherSettings }; //!< Selected weather scenario
|
||||
|
||||
private:
|
||||
// remote aircraft provider ("rap") bound
|
||||
void rapOnRecalculatedRenderedAircraft(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &snapshot);
|
||||
void rapOnRemoteProviderRemovedAircraft(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
// call with counters updated
|
||||
void callPhysicallyAddRemoteAircraft(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft);
|
||||
void callPhysicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &remoteCallsign, bool blinking = false);
|
||||
|
||||
//! Display a logged situation in simulator
|
||||
void displayLoggedSituationInSimulator(const BlackMisc::Aviation::CCallsign &cs, bool stopLogging, int times = 40);
|
||||
|
||||
bool m_blinkCycle = false; //!< used for highlighting
|
||||
qint64 m_highlightEndTimeMsEpoch = 0; //!< end highlighting
|
||||
int m_timerCounter = 0; //!< allows to calculate n seconds
|
||||
QTimer m_oneSecondTimer; //!< multi purpose timer with 1 sec. interval
|
||||
BlackMisc::Simulation::CSimulatedAircraftList m_highlightedAircraft; //!< all other aircraft are to be ignored
|
||||
BlackMisc::Aviation::CCallsignSet m_callsignsToBeRendered; //!< callsigns which will be rendered
|
||||
BlackMisc::CConnectionGuard m_remoteAircraftProviderConnections; //!< connected signal/slots
|
||||
|
||||
// statistics values of how often those functions are called
|
||||
// those are the added counters, overflow will not be an issue here (discussed in T171 review)
|
||||
int m_statsPhysicallyAddedAircraft = 0; //!< statistics, how many aircraft added
|
||||
int m_statsPhysicallyRemovedAircraft = 0; //!< statistics, how many aircraft removed
|
||||
};
|
||||
} // namespace
|
||||
|
||||
#endif // guard
|
||||
@@ -89,31 +89,31 @@ namespace BlackSimPlugin
|
||||
bool CSimulatorEmulated::logicallyAddRemoteAircraft(const CSimulatedAircraft &remoteAircraft)
|
||||
{
|
||||
if (canLog()) { m_monitorWidget->appendReceivingCall(Q_FUNC_INFO, remoteAircraft.toQString()); }
|
||||
return CSimulatorCommon::logicallyAddRemoteAircraft(remoteAircraft);
|
||||
return ISimulator::logicallyAddRemoteAircraft(remoteAircraft);
|
||||
}
|
||||
|
||||
bool CSimulatorEmulated::logicallyRemoveRemoteAircraft(const CCallsign &callsign)
|
||||
{
|
||||
if (canLog()) { m_monitorWidget->appendReceivingCall(Q_FUNC_INFO, callsign.toQString()); }
|
||||
return CSimulatorCommon::logicallyRemoveRemoteAircraft(callsign);
|
||||
return ISimulator::logicallyRemoveRemoteAircraft(callsign);
|
||||
}
|
||||
|
||||
int CSimulatorEmulated::physicallyRemoveMultipleRemoteAircraft(const CCallsignSet &callsigns)
|
||||
{
|
||||
if (canLog()) m_monitorWidget->appendReceivingCall(Q_FUNC_INFO, callsigns.toQString());
|
||||
return CSimulatorCommon::physicallyRemoveMultipleRemoteAircraft(callsigns);
|
||||
return ISimulator::physicallyRemoveMultipleRemoteAircraft(callsigns);
|
||||
}
|
||||
|
||||
bool CSimulatorEmulated::changeRemoteAircraftModel(const CSimulatedAircraft &aircraft)
|
||||
{
|
||||
if (canLog()) { m_monitorWidget->appendReceivingCall(Q_FUNC_INFO, aircraft.toQString()); }
|
||||
return CSimulatorCommon::changeRemoteAircraftEnabled(aircraft);
|
||||
return ISimulator::changeRemoteAircraftEnabled(aircraft);
|
||||
}
|
||||
|
||||
bool CSimulatorEmulated::changeRemoteAircraftEnabled(const CSimulatedAircraft &aircraft)
|
||||
{
|
||||
if (canLog()) { m_monitorWidget->appendReceivingCall(Q_FUNC_INFO, aircraft.toQString()); }
|
||||
return CSimulatorCommon::changeRemoteAircraftEnabled(aircraft);
|
||||
return ISimulator::changeRemoteAircraftEnabled(aircraft);
|
||||
}
|
||||
|
||||
bool CSimulatorEmulated::updateOwnSimulatorCockpit(const CSimulatedAircraft &aircraft, const CIdentifier &originator)
|
||||
@@ -176,7 +176,7 @@ namespace BlackSimPlugin
|
||||
void CSimulatorEmulated::highlightAircraft(const CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const CTime &displayTime)
|
||||
{
|
||||
if (canLog()) { m_monitorWidget->appendReceivingCall(Q_FUNC_INFO, aircraftToHighlight.toQString(), boolToTrueFalse(enableHighlight), displayTime.toQString()); }
|
||||
CSimulatorCommon::highlightAircraft(aircraftToHighlight, enableHighlight, displayTime);
|
||||
ISimulator::highlightAircraft(aircraftToHighlight, enableHighlight, displayTime);
|
||||
}
|
||||
|
||||
bool CSimulatorEmulated::parseCommandLine(const QString &commandLine, const CIdentifier &originator)
|
||||
@@ -308,7 +308,7 @@ namespace BlackSimPlugin
|
||||
int CSimulatorEmulated::physicallyRemoveAllRemoteAircraft()
|
||||
{
|
||||
if (canLog()) { m_monitorWidget->appendReceivingCall(Q_FUNC_INFO); }
|
||||
return CSimulatorCommon::physicallyRemoveAllRemoteAircraft();
|
||||
return ISimulator::physicallyRemoveAllRemoteAircraft();
|
||||
}
|
||||
|
||||
bool CSimulatorEmulated::parseDetails(const CSimpleCommandParser &parser)
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace BlackSimPlugin
|
||||
virtual bool isPhysicallyRenderedAircraft(const BlackMisc::Aviation::CCallsign &callsign) const override;
|
||||
virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override;
|
||||
|
||||
// functions just logged
|
||||
// ----- functions just logged -------
|
||||
virtual void highlightAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraftToHighlight, bool enableHighlight, const BlackMisc::PhysicalQuantities::CTime &displayTime) override;
|
||||
virtual bool logicallyAddRemoteAircraft(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft) override;
|
||||
virtual bool logicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override;
|
||||
@@ -129,7 +129,7 @@ namespace BlackSimPlugin
|
||||
// just logged
|
||||
virtual int physicallyRemoveAllRemoteAircraft() override;
|
||||
|
||||
//! \copydoc BlackCore::CSimulatorCommon::parseDetails
|
||||
//! \copydoc BlackCore::ISimulator::parseDetails
|
||||
virtual bool parseDetails(const BlackMisc::CSimpleCommandParser &parser) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace BlackSimPlugin
|
||||
CAirportList CSimulatorFsCommon::getAirportsInRange() const
|
||||
{
|
||||
if (!m_airportsInRangeFromSimulator.isEmpty()) { return m_airportsInRangeFromSimulator; }
|
||||
return CSimulatorCommon::getAirportsInRange();
|
||||
return ISimulator::getAirportsInRange();
|
||||
}
|
||||
|
||||
void CSimulatorFsCommon::onSwiftDbAirportsRead()
|
||||
@@ -133,7 +133,7 @@ namespace BlackSimPlugin
|
||||
{
|
||||
m_airportsInRangeFromSimulator.updateMissingParts(webServiceAirports);
|
||||
}
|
||||
CSimulatorCommon::onSwiftDbAirportsRead();
|
||||
ISimulator::onSwiftDbAirportsRead();
|
||||
}
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
|
||||
#include <blackcore/simulatorcommon.h>
|
||||
|
||||
namespace BlackSimPlugin
|
||||
{
|
||||
namespace FsCommon
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace BlackSimPlugin
|
||||
IWeatherGridProvider *weatherGridProvider,
|
||||
IClientProvider *clientProvider,
|
||||
QObject *parent) :
|
||||
CSimulatorCommon(info, ownAircraftProvider, renderedAircraftProvider, weatherGridProvider, clientProvider, parent)
|
||||
ISimulator(info, ownAircraftProvider, renderedAircraftProvider, weatherGridProvider, clientProvider, parent)
|
||||
{
|
||||
CSimulatorPluginCommon::registerHelp();
|
||||
}
|
||||
@@ -75,19 +75,19 @@ namespace BlackSimPlugin
|
||||
this->showInterpolationDisplay();
|
||||
return true;
|
||||
}
|
||||
return CSimulatorCommon::parseDetails(parser);
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSimulatorPluginCommon::unload()
|
||||
{
|
||||
this->deleteInterpolationDisplay();
|
||||
CSimulatorCommon::unload();
|
||||
ISimulator::unload();
|
||||
}
|
||||
|
||||
bool CSimulatorPluginCommon::disconnectFrom()
|
||||
{
|
||||
this->deleteInterpolationDisplay();
|
||||
return CSimulatorCommon::disconnectFrom();
|
||||
return ISimulator::disconnectFrom();
|
||||
}
|
||||
|
||||
void CSimulatorPluginCommon::registerHelp()
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#ifndef BLACKSIMPLUGIN_COMMON_SIMULATORPLUGINCOMMON_H
|
||||
#define BLACKSIMPLUGIN_COMMON_SIMULATORPLUGINCOMMON_H
|
||||
|
||||
#include "blackcore/simulatorcommon.h"
|
||||
#include "blackcore/simulator.h"
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace BlackSimPlugin
|
||||
namespace Common
|
||||
{
|
||||
//! Common base class for simulator plugins
|
||||
class CSimulatorPluginCommon : public BlackCore::CSimulatorCommon
|
||||
class CSimulatorPluginCommon : public BlackCore::ISimulator
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(BlackCore::ISimulator)
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
#include "xplanempaircraft.h"
|
||||
#include "plugins/simulator/xplaneconfig/simulatorxplaneconfig.h"
|
||||
#include "plugins/simulator/plugincommon/simulatorplugincommon.h"
|
||||
#include "blackcore/simulator.h"
|
||||
#include "blackcore/simulatorcommon.h"
|
||||
#include "blackmisc/simulation/aircraftmodellist.h"
|
||||
#include "blackmisc/simulation/data/modelcaches.h"
|
||||
#include "blackmisc/simulation/settings/simulatorsettings.h"
|
||||
|
||||
Reference in New Issue
Block a user