refs #409 Refactor matching implementation in MSFS drivers

CAircraftMapper used to be designed around FSX only. CAircraftMatcher
instead is more generic for different MSFS versions. Therefore it is
replaced with the latter. This change also gets rid of the singleton and
its drawbacks by using the plugin storage.
Last but not least it implements the first model matching for FS9.
This commit is contained in:
Roland Winklmeier
2015-05-21 13:34:53 +02:00
parent 74b6bb9756
commit 6995ad7063
6 changed files with 96 additions and 134 deletions

View File

@@ -28,10 +28,10 @@ namespace BlackSimPlugin
{
namespace Fs9
{
CFs9Client::CFs9Client(
BlackCore::IInterpolator *interpolator, QObject *owner, const BlackMisc::Aviation::CCallsign &callsign, const CTime &updateInterval) :
CFs9Client::CFs9Client(const CCallsign &callsign, const QString &modelName,
BlackCore::IInterpolator *interpolator, const CTime &updateInterval, QObject *owner) :
CDirectPlayPeer(owner, callsign),
m_updateInterval(updateInterval), m_interpolator(interpolator)
m_updateInterval(updateInterval), m_interpolator(interpolator), m_modelName(modelName)
{
}
@@ -183,8 +183,9 @@ namespace BlackSimPlugin
callsign.toQString().toWCharArray(wszPlayername.data());
wszPlayername[callsign.toQString().size()] = 0;
Q_ASSERT(!m_modelName.isEmpty());
ZeroMemory(&m_playerInfo, sizeof(PLAYER_INFO_STRUCT));
strcpy(m_playerInfo.szAircraft, "Boeing 737-400 Paint1");
strcpy(m_playerInfo.szAircraft, qPrintable(m_modelName));
m_playerInfo.dwFlags = 6;
// Prepare and set the player information structure.
@@ -222,7 +223,7 @@ namespace BlackSimPlugin
MPChangePlayerPlane mpChangePlayerPlane;
mpChangePlayerPlane.engine = CFs9Sdk::ENGINE_TYPE_JET;
mpChangePlayerPlane.aircraft_name = "Boeing 737-400";
mpChangePlayerPlane.aircraft_name = m_modelName;
QByteArray message;
MultiPlayerPacketParser::writeType(message, CFs9Sdk::MULTIPLAYER_PACKET_ID_CHANGE_PLAYER_PLANE);
MultiPlayerPacketParser::writeSize(message, mpChangePlayerPlane.size());

View File

@@ -39,7 +39,9 @@ namespace BlackSimPlugin
};
//! Constructor
CFs9Client(BlackCore::IInterpolator *interpolator, QObject *owner, const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::PhysicalQuantities::CTime &updateInterval);
CFs9Client(const BlackMisc::Aviation::CCallsign &callsign, const QString &modelName,
BlackCore::IInterpolator *interpolator, const BlackMisc::PhysicalQuantities::CTime &updateInterval,
QObject *owner);
//! Destructor
virtual ~CFs9Client();
@@ -89,6 +91,7 @@ namespace BlackSimPlugin
BlackMisc::PhysicalQuantities::CTime m_updateInterval;
BlackCore::IInterpolator *m_interpolator = nullptr;
QString m_modelName;
int m_timerId = 0;
IDirectPlay8Address *m_hostAddress = nullptr;

View File

@@ -20,6 +20,7 @@
#include "blackmisc/project.h"
#include "blackmisc/logmessage.h"
#include "blackmisc/propertyindexallclasses.h"
#include "blackmisc/simulation/fscommon/fscommonutil.h"
#include <QTimer>
#include <algorithm>
@@ -30,6 +31,7 @@ using namespace BlackMisc::Simulation;
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Geo;
using namespace BlackMisc::Simulation;
using namespace BlackMisc::Simulation::FsCommon;
using namespace BlackSimPlugin::Fs9;
using namespace BlackSimPlugin::FsCommon;
@@ -52,10 +54,17 @@ namespace BlackSimPlugin
IRemoteAircraftProvider *remoteAircraftProvider,
IPluginStorageProvider *pluginStorageProvider,
QObject *parent) :
CSimulatorFsCommon(info, ownAircraftProvider, remoteAircraftProvider, pluginStorageProvider, parent)
CSimulatorFsCommon(info, ownAircraftProvider, remoteAircraftProvider, pluginStorageProvider,
aircraftObjectsDir(), excludeDirectories(), parent)
{
connect(lobbyClient.data(), &CLobbyClient::disconnected, this, std::bind(&CSimulatorFs9::simulatorStatusChanged, this, 0));
this->m_interpolator = new BlackCore::CInterpolatorLinear(remoteAircraftProvider, this);
m_modelMatcher.setDefaultModel(CAircraftModel(
"Boeing 737-400",
CAircraftModel::TypeModelMatchingDefaultModel,
"B737-400 default model",
CAircraftIcaoData(CAircraftIcaoCode("B734", "L2J"), CAirlineIcaoCode(), "FFFFFF")
));
}
bool CSimulatorFs9::isConnected() const
@@ -111,7 +120,17 @@ namespace BlackSimPlugin
this->physicallyRemoveRemoteAircraft(callsign);
}
CFs9Client *client = new CFs9Client(m_interpolator, this, callsign, CTime(25, CTimeUnit::ms()));
CSimulatedAircraft newRemoteAircraftCopy(newRemoteAircraft);
// matched models
CAircraftModel aircraftModel = getClosestMatch(newRemoteAircraftCopy);
Q_ASSERT(newRemoteAircraft.getCallsign() == aircraftModel.getCallsign());
updateAircraftModel(newRemoteAircraft.getCallsign(), aircraftModel, simulatorOriginator());
updateAircraftRendered(newRemoteAircraft.getCallsign(), true, simulatorOriginator());
CSimulatedAircraft aircraftAfterModelApplied (getAircraftInRangeForCallsign(newRemoteAircraft.getCallsign()));
aircraftAfterModelApplied.setRendered(true);
emit modelMatchingCompleted(aircraftAfterModelApplied);
CFs9Client *client = new CFs9Client(callsign, aircraftModel.getModelString(), m_interpolator, CTime(25, CTimeUnit::ms()), this);
client->setHostAddress(fs9Host->getHostAddress());
client->setPlayerUserId(fs9Host->getPlayerUserId());

View File

@@ -10,7 +10,7 @@
#include "simulator_fscommon.h"
#include "blackmisc/logmessage.h"
#include "blackmisc/simulation/fscommon/modelmappingsprovidervpilot.h"
#include "blackmisc/simulation/fscommon/fscommonutil.h"
#include "blackmisc/blackmiscfreefunctions.h"
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Simulation;
@@ -30,22 +30,37 @@ namespace BlackSimPlugin
IOwnAircraftProvider *ownAircraftProvider,
IRemoteAircraftProvider *renderedAircraftProvider,
IPluginStorageProvider *pluginStorageProvider,
QString simRootDirectory,
QStringList excludedDirectories,
QObject *parent) :
CSimulatorCommon(info, ownAircraftProvider, renderedAircraftProvider, pluginStorageProvider, parent),
m_fsuipc(new CFsuipc())
m_fsuipc(new CFsuipc()),
m_aircraftCfgParser(simRootDirectory, excludedDirectories),
m_modelMatcher(CAircraftMatcher::AllModes, this)
{
// hack to init mapper
CAircraftMapper *mapper = mapperInstance();
connect(mapper, &CAircraftMapper::initCompleted, this, &CSimulatorFsCommon::ps_mapperInitialized);
mapper->initCompletelyInBackground();
connect(&m_modelMatcher, &CAircraftMatcher::initializationFinished, this, &CSimulatorFsCommon::ps_mapperInitialized);
auto modelMappingsProvider = std::unique_ptr<IModelMappingsProvider>{ BlackMisc::make_unique<CModelMappingsProviderVPilot>(true) };
m_modelMatcher.setModelMappingProvider(std::move(modelMappingsProvider));
CVariant aircraftCfg = getPluginData(this, "aircraft_cfg");
if (aircraftCfg.isValid())
{
m_modelMatcher.setInstalledModels(aircraftCfg.value<CAircraftCfgEntriesList>().toAircraftModelList());
}
else
{
connect(&m_aircraftCfgParser, &CAircraftCfgParser::parsingFinished, this, &CSimulatorFsCommon::ps_aircraftCfgParsingFinished);
m_aircraftCfgParser.parse();
}
}
CSimulatorFsCommon::~CSimulatorFsCommon()
{ }
void CSimulatorFsCommon::ps_mapperInitialized(bool success)
void CSimulatorFsCommon::ps_mapperInitialized()
{
if (success) { emit this->installedAircraftModelsChanged(); }
emit this->installedAircraftModelsChanged();
}
bool CSimulatorFsCommon::disconnectFrom()
@@ -101,139 +116,41 @@ namespace BlackSimPlugin
void CSimulatorFsCommon::reverseLookupIcaoData(CAircraftModel &model)
{
if (mapperInstance() && mapperInstance()->isInitialized())
if (m_modelMatcher.isInitialized())
{
// reverse lookup of ICAO
CAircraftIcaoData icao = mapperInstance()->getIcaoForModelString(model.getModelString());
CAircraftIcaoData icao = m_modelMatcher.getIcaoForModelString(model.getModelString());
icao.updateMissingParts(model.getIcao());
model.setIcao(icao); // now best ICAO info in model
}
}
CAircraftMapper *CSimulatorFsCommon::mapperInstance()
CAircraftModel CSimulatorFsCommon::getClosestMatch(const CSimulatedAircraft &remoteAircraft)
{
static CModelMappingsProviderVPilot *mappings = new CModelMappingsProviderVPilot(true);
// tries to access simObjectsDir, if this is an mapped remote directory
// init might hang for a while
static CAircraftMapper *mapper = new CAircraftMapper(
std::unique_ptr<CModelMappingsProviderVPilot>(mappings), // currently hard wired
simObjectsDir()
);
return mapper;
}
CAircraftModel CSimulatorFsCommon::modelMatching(const CSimulatedAircraft &remoteAircraft)
{
//! \todo Model Matching before models are read
// default model
CAircraftModel aircraftModel(remoteAircraft); // set defaults
// Manually set string?
if (remoteAircraft.getModel().hasManuallySetString())
{
// manual set model, maybe update missing parts
aircraftModel.updateMissingParts(remoteAircraft.getModel());
CSimulatorFsCommon::reverseLookupIcaoData(aircraftModel);
return aircraftModel;
}
// mapper ready?
if (!mapperInstance()->isInitialized())
{
// will be removed later, just for experimental version
aircraftModel = CAircraftMapper::getDefaultModel();
aircraftModel.setCallsign(remoteAircraft.getCallsign());
CLogMessage(static_cast<CSimulatorFsCommon *>(nullptr)).warning("Mapper not ready, set to default model");
return aircraftModel;
}
// Model by queried string
const CClient remoteClient = remoteAircraft.getClient();
if (remoteClient.getAircraftModel().hasQueriedModelString())
{
QString directModelString = remoteClient.getAircraftModel().getModelString();
if (!directModelString.isEmpty() && mapperInstance()->containsModelWithTitle(directModelString))
{
aircraftModel = mapperInstance()->getModelWithTitle(directModelString);
aircraftModel.setModelType(CAircraftModel::TypeQueriedFromNetwork);
}
}
// ICAO to model
if (!aircraftModel.hasModelString())
{
CAircraftIcaoData icao = remoteAircraft.getIcaoInfo();
BlackMisc::Network::CAircraftMappingList mappingList = mapperInstance()->getAircraftMappingList().findByIcaoAircraftAndAirlineDesignator(icao, true);
if (!mappingList.isEmpty())
{
CAircraftModel modelFromMappings = mappingList.front().getModel();
// now turn the model from the mapping rules into a model from the simulator which has more metadata
aircraftModel = mapperInstance()->getModelWithTitle(modelFromMappings.getModelString());
Q_ASSERT(aircraftModel.getModelString() == modelFromMappings.getModelString());
aircraftModel.updateMissingParts(modelFromMappings); // update ICAO
aircraftModel.setModelType(CAircraftModel::TypeModelMatching);
}
}
// default or sanity check
if (!aircraftModel.hasModelString())
{
aircraftModel = CAircraftMapper::getDefaultModel();
}
else
{
// check, do we have the model on disk
if (!mapperInstance()->containsModelWithTitle(aircraftModel.getModelString()))
{
const QString m = QString("Missing model: %1").arg(aircraftModel.getModelString());
Q_ASSERT_X(false, "modelMatching", m.toLocal8Bit().constData());
}
}
aircraftModel.setCallsign(remoteAircraft.getCallsign());
Q_ASSERT(!aircraftModel.getCallsign().isEmpty());
Q_ASSERT(aircraftModel.hasModelString());
Q_ASSERT(aircraftModel.getModelType() != CAircraftModel::TypeUnknown);
return aircraftModel;
}
QString CSimulatorFsCommon::simObjectsDir()
{
//! \todo add FS9 dir
QString dir = CFsCommonUtil::fsxSimObjectsDirFromRegistry();
if (!dir.isEmpty()) { return dir; }
return "P:/FlightSimulatorX (MSI)/SimObjects";
// "p:/temp/SimObjects"
return m_modelMatcher.getClosestMatch(remoteAircraft);
}
CAircraftModelList CSimulatorFsCommon::getInstalledModels() const
{
if (!mapperInstance()) { return CAircraftModelList(); }
return mapperInstance()->getAircraftCfgEntriesList().toAircraftModelList();
return m_aircraftCfgParser.getAircraftCfgEntriesList().toAircraftModelList();
}
CAircraftIcaoData CSimulatorFsCommon::getIcaoForModelString(const QString &modelString) const
{
if (!mapperInstance()) { return CAircraftIcaoData(); }
return mapperInstance()->getIcaoForModelString(modelString);
if (!m_modelMatcher.isInitialized()) { return CAircraftIcaoData(); }
return m_modelMatcher.getIcaoForModelString(modelString);
}
void CSimulatorFsCommon::reloadInstalledModels()
{
if (mapperInstance())
{
mapperInstance()->markUninitialized();
mapperInstance()->initCompletelyInBackground();
}
m_aircraftCfgParser.parse();
}
CPixmap CSimulatorFsCommon::iconForModel(const QString &modelString) const
{
static const CPixmap empty;
if (modelString.isEmpty() || !mapperInstance()->isInitialized()) { return empty; }
CAircraftCfgEntriesList cfgEntries = mapperInstance()->getAircraftCfgEntriesList().findByTitle(modelString);
if (modelString.isEmpty()) { return empty; }
CAircraftCfgEntriesList cfgEntries = m_aircraftCfgParser.getAircraftCfgEntriesList().findByTitle(modelString);
if (cfgEntries.isEmpty())
{
CLogMessage(this).warning("No .cfg entry for '%1'") << modelString;
@@ -292,5 +209,14 @@ namespace BlackSimPlugin
CSimulatorCommon::enableDebugMessages(driver, interpolator);
}
void CSimulatorFsCommon::ps_aircraftCfgParsingFinished()
{
setPluginData(this, "aircraft_cfg", m_aircraftCfgParser.getAircraftCfgEntriesList().toCVariant());
m_modelMatcher.setInstalledModels(m_aircraftCfgParser.getAircraftCfgEntriesList().toAircraftModelList());
// Now the matcher has all required information to be initialized
m_modelMatcher.init();
}
} // namespace
} // namespace

View File

@@ -14,7 +14,8 @@
#include "blackcore/simulator_common.h"
#include "blackcore/interpolator.h"
#include "blackmisc/simulation/fscommon/aircraftmapper.h"
#include "blackmisc/simulation/fscommon/aircraftmatcher.h"
#include "blackmisc/simulation/fscommon/aircraftcfgparser.h"
#include "fsuipc.h"
#include <QObject>
@@ -37,10 +38,7 @@ namespace BlackSimPlugin
bool isFsuipcConnected() const;
//! Experimental model matching
static BlackMisc::Simulation::CAircraftModel modelMatching(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft);
//! SimObjects directory
static QString simObjectsDir();
BlackMisc::Simulation::CAircraftModel getClosestMatch(const BlackMisc::Simulation::CSimulatedAircraft &remoteAircraft);
//! \copydoc ISimulator::isPaused
virtual bool isPaused() const override { return m_simPaused; }
@@ -84,6 +82,8 @@ namespace BlackSimPlugin
BlackMisc::Simulation::IOwnAircraftProvider *ownAircraftProvider,
BlackMisc::Simulation::IRemoteAircraftProvider *renderedAircraftProvider,
BlackMisc::IPluginStorageProvider *pluginStorageProvider,
QString simRootDirectory,
QStringList excludedDirectories,
QObject *parent = nullptr);
QString simulatorDetails; //!< describes version etc.
@@ -99,6 +99,8 @@ namespace BlackSimPlugin
BlackMisc::Aviation::CComSystem m_simCom2; //!< cockpit COM2 state in simulator
BlackMisc::Aviation::CTransponder m_simTransponder; //!< cockpit xpdr state in simulator
BlackMisc::Simulation::FsCommon::CAircraftCfgParser m_aircraftCfgParser; //!< aircraft.cfg parser
//! Set own model
void setOwnAircraftModel(const BlackMisc::Simulation::CAircraftModel &model);
@@ -106,15 +108,17 @@ namespace BlackSimPlugin
void setOwnAircraftModel(const QString &modelName);
//! Reverse lookup
static void reverseLookupIcaoData(BlackMisc::Simulation::CAircraftModel &model);
void reverseLookupIcaoData(BlackMisc::Simulation::CAircraftModel &model);
//! Get the mapper singleton
static BlackMisc::Simulation::FsCommon::CAircraftMapper *mapperInstance();
BlackMisc::Simulation::FsCommon::CAircraftMatcher m_modelMatcher; //!< Model matcher
protected slots:
//! Mapper has been initialized
void ps_mapperInitialized(bool success);
void ps_mapperInitialized();
//! aircraft.cfg files parsing is finished
void ps_aircraftCfgParsingFinished();
};
} // namespace

View File

@@ -19,6 +19,7 @@
#include "blackmisc/aviation/airportlist.h"
#include "blackmisc/logmessage.h"
#include "blackmisc/network/aircraftmappinglist.h"
#include "blackmisc/simulation/fscommon/fscommonutil.h"
#include <QTimer>
#include <type_traits>
@@ -43,7 +44,8 @@ namespace BlackSimPlugin
IRemoteAircraftProvider *remoteAircraftProvider,
IPluginStorageProvider *pluginStorageProvider,
QObject *parent) :
CSimulatorFsCommon(info, ownAircraftProvider, remoteAircraftProvider, pluginStorageProvider, parent)
CSimulatorFsCommon(info, ownAircraftProvider, remoteAircraftProvider, pluginStorageProvider,
simObjectsDir(), excludeDirectories(), parent)
{
Q_ASSERT(ownAircraftProvider);
Q_ASSERT(remoteAircraftProvider);
@@ -51,6 +53,12 @@ namespace BlackSimPlugin
m_useFsuipc = false; // do not use FSUIPC at the moment with FSX
this->m_interpolator = new CInterpolatorLinear(remoteAircraftProvider, this);
m_modelMatcher.setDefaultModel(CAircraftModel(
"Boeing 737-800 Paint1",
CAircraftModel::TypeModelMatchingDefaultModel,
"B737-800 default model",
CAircraftIcaoData(CAircraftIcaoCode("B738", "L2J"), CAirlineIcaoCode(), "FFFFFF")
));
}
CSimulatorFsx::~CSimulatorFsx()
@@ -155,7 +163,7 @@ namespace BlackSimPlugin
++m_nextObjID;
// matched models
CAircraftModel aircraftModel = modelMatching(newRemoteAircraft);
CAircraftModel aircraftModel = getClosestMatch(newRemoteAircraft);
Q_ASSERT_X(newRemoteAircraft.getCallsign() == aircraftModel.getCallsign(), Q_FUNC_INFO, "mismatching callsigns");
this->updateAircraftModel(callsign, aircraftModel, simulatorOriginator());
@@ -899,5 +907,6 @@ namespace BlackSimPlugin
{
m_timer->stop();
}
} // namespace
} // namespace