refs #438, plugin loading testing session + meeting results

* simulator common, many members now private (info -> read only)
* renamed printDirectPlayError -> logDirectPlayError
* (re)added ASSERT for FS9
* removed parent from listener (with parent no moveToThread)
* removed QFuture / QConcurrent as we have agreed to do
* unloading a plugin no longer automatically restarts all listeners
  this allows a user to set one particualar simulator in the GUI and ony wait for that
* stop listener from own signal
This commit is contained in:
Klaus Basan
2015-06-04 18:25:40 +02:00
parent e822c9f7d2
commit d603b28697
20 changed files with 124 additions and 159 deletions

View File

@@ -14,6 +14,7 @@
#include "context_application.h" #include "context_application.h"
#include "context_network_impl.h" #include "context_network_impl.h"
#include "context_runtime.h" #include "context_runtime.h"
#include "blackcore/blackcorefreefunctions.h"
#include "blackmisc/propertyindexvariantmap.h" #include "blackmisc/propertyindexvariantmap.h"
#include "blackmisc/logmessage.h" #include "blackmisc/logmessage.h"
#include "blackmisc/loghandler.h" #include "blackmisc/loghandler.h"
@@ -130,7 +131,7 @@ namespace BlackCore
void CContextSimulator::stopSimulatorPlugin() void CContextSimulator::stopSimulatorPlugin()
{ {
this->unloadSimulatorPlugin(false); this->unloadSimulatorPlugin();
} }
int CContextSimulator::getSimulatorStatus() const int CContextSimulator::getSimulatorStatus() const
@@ -355,6 +356,7 @@ namespace BlackCore
Q_ASSERT(getIContextApplication()); Q_ASSERT(getIContextApplication());
Q_ASSERT(getIContextApplication()->isUsingImplementingObject()); Q_ASSERT(getIContextApplication()->isUsingImplementingObject());
Q_ASSERT(!simulatorInfo.isUnspecified()); Q_ASSERT(!simulatorInfo.isUnspecified());
Q_ASSERT(BlackCore::isCurrentThreadApplicationThread()); // only run in main thread
// error if we do not have any plugins // error if we do not have any plugins
if (m_simulatorPlugins.isEmpty()) if (m_simulatorPlugins.isEmpty())
@@ -364,12 +366,14 @@ namespace BlackCore
} }
// Is the plugin already loaded? // Is the plugin already loaded?
if (m_simulatorPlugin && m_simulatorPlugin->info == simulatorInfo) if (m_simulatorPlugin &&
(m_simulatorPlugin->info == simulatorInfo || simulatorInfo.isAuto()))
{ {
return true; return true;
} }
unloadSimulatorPlugin(false); // old plugin unloaded stopSimulatorListeners(); // we make sure all listeners are stopped and restart those we need
unloadSimulatorPlugin(); // old plugin unloaded
// now we have a state where no driver is loaded // now we have a state where no driver is loaded
if (withListener) if (withListener)
@@ -393,7 +397,7 @@ namespace BlackCore
} }
ISimulatorFactory *factory = getSimulatorFactory(simulatorInfo); ISimulatorFactory *factory = getSimulatorFactory(simulatorInfo);
Q_ASSERT(factory); Q_ASSERT_X(factory, Q_FUNC_INFO, "no factory");
// We assume we run in the same process as the own aircraft context // We assume we run in the same process as the own aircraft context
// Hence we pass in memory reference to own aircraft object // Hence we pass in memory reference to own aircraft object
@@ -428,7 +432,7 @@ namespace BlackCore
Q_ASSERT(c); Q_ASSERT(c);
Q_UNUSED(c); Q_UNUSED(c);
// connect with network // use network to initally add aircraft
IContextNetwork *networkContext = this->getIContextNetwork(); IContextNetwork *networkContext = this->getIContextNetwork();
Q_ASSERT(networkContext); Q_ASSERT(networkContext);
Q_ASSERT(networkContext->isLocalObject()); Q_ASSERT(networkContext->isLocalObject());
@@ -440,7 +444,7 @@ namespace BlackCore
m_simulatorPlugin->simulator->logicallyAddRemoteAircraft(simulatedAircraft); m_simulatorPlugin->simulator->logicallyAddRemoteAircraft(simulatedAircraft);
} }
// try to connect // try to connect to simulator
m_simulatorPlugin->simulator->connectTo(); m_simulatorPlugin->simulator->connectTo();
emit simulatorPluginChanged(this->m_simulatorPlugin->info); emit simulatorPluginChanged(this->m_simulatorPlugin->info);
CLogMessage(this).info("Simulator plugin loaded: %1") << this->m_simulatorPlugin->info.toQString(true); CLogMessage(this).info("Simulator plugin loaded: %1") << this->m_simulatorPlugin->info.toQString(true);
@@ -471,7 +475,7 @@ namespace BlackCore
if (this->m_simulatorPlugin) if (this->m_simulatorPlugin)
{ {
// wrong or disconnected plugin, we start from the scratch // wrong or disconnected plugin, we start from the scratch
this->unloadSimulatorPlugin(false); this->unloadSimulatorPlugin();
} }
PluginData *plugin = findPlugin(simulatorInfo); PluginData *plugin = findPlugin(simulatorInfo);
@@ -483,31 +487,32 @@ namespace BlackCore
if (!plugin->listener) if (!plugin->listener)
{ {
ISimulatorFactory *factory = getSimulatorFactory(simulatorInfo); if (!m_listenersThread.isRunning())
Q_ASSERT(factory); {
m_listenersThread.setObjectName("CContextSimulator:Thread for listeners");
m_listenersThread.start(QThread::LowPriority);
}
plugin->listener = factory->createListener(simulatorInfo, this); ISimulatorFactory *factory = getSimulatorFactory(simulatorInfo);
Q_ASSERT_X(factory, Q_FUNC_INFO, "No simulator factory");
plugin->listener = factory->createListener(simulatorInfo);
bool c = connect(plugin->listener, &ISimulatorListener::simulatorStarted, this, &CContextSimulator::ps_simulatorStarted); bool c = connect(plugin->listener, &ISimulatorListener::simulatorStarted, this, &CContextSimulator::ps_simulatorStarted);
if (!c) if (!c)
{ {
CLogMessage(this).error("Unable to use '%1'") << simulatorInfo.toQString(); CLogMessage(this).error("Unable to use '%1'") << simulatorInfo.toQString();
return; return;
} }
Q_ASSERT_X(!plugin->listener->parent(), Q_FUNC_INFO, "Objects with parent cannot be moved to thread");
plugin->listener->moveToThread(&m_listenersThread); plugin->listener->moveToThread(&m_listenersThread);
} }
ISimulatorListener *listener = plugin->listener; ISimulatorListener *listener = plugin->listener;
Q_ASSERT_X(listener, Q_FUNC_INFO, "No listener"); Q_ASSERT_X(listener, Q_FUNC_INFO, "No listener");
if (!m_listenersThread.isRunning()) bool s = QMetaObject::invokeMethod(listener, "start", Qt::QueuedConnection);
{
m_listenersThread.start(QThread::LowPriority);
}
bool s = QMetaObject::invokeMethod(listener, "start");
Q_ASSERT_X(s, Q_FUNC_INFO, "cannot invoke method"); Q_ASSERT_X(s, Q_FUNC_INFO, "cannot invoke method");
Q_UNUSED(s); Q_UNUSED(s);
CLogMessage(this).debug() << "Listening for simulator: " << simulatorInfo.toQString(true);
} }
void CContextSimulator::listenForAllSimulators() void CContextSimulator::listenForAllSimulators()
@@ -523,7 +528,7 @@ namespace BlackCore
} }
} }
void CContextSimulator::unloadSimulatorPlugin(bool startListeners) void CContextSimulator::unloadSimulatorPlugin()
{ {
if (m_simulatorPlugin) if (m_simulatorPlugin)
{ {
@@ -543,11 +548,6 @@ namespace BlackCore
emit simulatorPluginChanged(CSimulatorPluginInfo()); emit simulatorPluginChanged(CSimulatorPluginInfo());
} }
} }
if (startListeners)
{
this->listenForAllSimulators();
}
} }
void CContextSimulator::ps_addRemoteAircraft(const CSimulatedAircraft &remoteAircraft) void CContextSimulator::ps_addRemoteAircraft(const CSimulatedAircraft &remoteAircraft)
@@ -587,14 +587,7 @@ namespace BlackCore
if (!statusEnum.testFlag(ISimulator::Connected)) if (!statusEnum.testFlag(ISimulator::Connected))
{ {
// we got disconnected, plugin no longer needed // we got disconnected, plugin no longer needed
unloadSimulatorPlugin(false); unloadSimulatorPlugin();
// do not immediately listen again, but allow some time for the simulator to shutdown
// otherwise we risk reconnecting to a closing simulator
BlackMisc::singleShot(1000, QThread::currentThread(), [ = ]()
{
listenForAllSimulators();
});
} }
emit simulatorStatusChanged(status); emit simulatorStatusChanged(status);
} }

View File

@@ -201,7 +201,7 @@ namespace BlackCore
bool loadSimulatorPlugin(const BlackMisc::Simulation::CSimulatorPluginInfo &simulatorInfo, bool withListeners); bool loadSimulatorPlugin(const BlackMisc::Simulation::CSimulatorPluginInfo &simulatorInfo, bool withListeners);
//! Unload plugin, if desired restart listeners //! Unload plugin, if desired restart listeners
void unloadSimulatorPlugin(bool startListeners); void unloadSimulatorPlugin();
//! Find and catalog all simulator plugins //! Find and catalog all simulator plugins
void findSimulatorPlugins(); void findSimulatorPlugins();

View File

@@ -59,8 +59,15 @@ namespace BlackCore
} }
} }
ISimulatorListener::ISimulatorListener(const CSimulatorPluginInfo &info, QObject *parent) : ISimulatorListener::ISimulatorListener(const CSimulatorPluginInfo &info) :
QObject(parent), m_info(info) QObject(), m_info(info)
{ } {
this->setObjectName("ISimulatorListener:" + info.toQString());
// stop listener after it reports simulator ready
bool s = connect(this, &ISimulatorListener::simulatorStarted, this, &ISimulatorListener::stop, Qt::QueuedConnection);
Q_ASSERT_X(s, Q_FUNC_INFO, "connect failed");
Q_UNUSED(s)
}
} // namespace } // namespace

View File

@@ -245,7 +245,7 @@ namespace BlackCore
//! Constructor //! Constructor
//! \sa ISimulatorFactory::createListener(). //! \sa ISimulatorFactory::createListener().
//! \note msvc2015: use inherited constructor //! \note msvc2015: use inherited constructor
ISimulatorListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info, QObject *parent); ISimulatorListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info);
//! Destructor //! Destructor
virtual ~ISimulatorListener() = default; virtual ~ISimulatorListener() = default;
@@ -289,8 +289,7 @@ namespace BlackCore
BlackMisc::IPluginStorageProvider *pluginStorageProvider) = 0; BlackMisc::IPluginStorageProvider *pluginStorageProvider) = 0;
//! Simulator listener instance //! Simulator listener instance
virtual ISimulatorListener *createListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info, QObject *parent = nullptr) = 0; virtual ISimulatorListener *createListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info) = 0;
}; };
} // namespace } // namespace

View File

@@ -136,10 +136,13 @@ namespace BlackCore
//! Override situation from current interpolator values, if any! //! Override situation from current interpolator values, if any!
bool setInitialAircraftSituation(BlackMisc::Simulation::CSimulatedAircraft &aircraft) const; bool setInitialAircraftSituation(BlackMisc::Simulation::CSimulatedAircraft &aircraft) const;
protected:
IInterpolator *m_interpolator = nullptr; //!< interpolator instance
bool m_pausedSimFreezesInterpolation = false; //!< paused simulator will also pause interpolation (so AI aircraft will hold)
private:
bool m_debugMessages = false; //!< Display debug messages bool m_debugMessages = false; //!< Display debug messages
bool m_blinkCycle = false; //!< use for highlighting bool m_blinkCycle = false; //!< use for highlighting
bool m_pausedSimFreezesInterpolation = false; //!< paused simulator will also pause interpolation (so AI aircraft will hold)
IInterpolator *m_interpolator = nullptr; //!< interpolator instance
qint64 m_highlightEndTimeMsEpoch = 0; //!< end highlighting qint64 m_highlightEndTimeMsEpoch = 0; //!< end highlighting
int m_timerCounter = 0; //!< allows to calculate n seconds int m_timerCounter = 0; //!< allows to calculate n seconds
QTimer m_oneSecondTimer {this}; //!< timer QTimer m_oneSecondTimer {this}; //!< timer
@@ -150,9 +153,7 @@ namespace BlackCore
int m_maxRenderedAircraft = MaxAircraftInfinite; //!< max.rendered aircraft int m_maxRenderedAircraft = MaxAircraftInfinite; //!< max.rendered aircraft
BlackMisc::PhysicalQuantities::CLength m_maxRenderedDistance { 0.0, BlackMisc::PhysicalQuantities::CLengthUnit::nullUnit()}; //!< max.distance for rendering BlackMisc::PhysicalQuantities::CLength m_maxRenderedDistance { 0.0, BlackMisc::PhysicalQuantities::CLengthUnit::nullUnit()}; //!< max.distance for rendering
QList<QMetaObject::Connection> m_remoteAircraftProviderConnections; //!< connected signal/slots QList<QMetaObject::Connection> m_remoteAircraftProviderConnections; //!< connected signal/slots
}; };
} // namespace } // namespace
#endif // guard #endif // guard

View File

@@ -22,21 +22,6 @@ namespace BlackMisc
//! Describing a simulator plugin //! Describing a simulator plugin
class BLACKMISC_EXPORT CSimulatorPluginInfo : public BlackMisc::CValueObject<CSimulatorPluginInfo> class BLACKMISC_EXPORT CSimulatorPluginInfo : public BlackMisc::CValueObject<CSimulatorPluginInfo>
{ {
//! The _identifier_ property identifies the plugin itself and must be uniqe.
Q_PROPERTY(QString identifier READ getIdentifier)
//! The _name_ property is a human-readable plugin name.
Q_PROPERTY(QString same READ getName)
//! The _simulator_ property specifies which simulator the plugin handles.
//! There cannot be two plugins loaded for the same simulator.
//! swift enables some features for particular simulators. Currently recognized are:
//! fsx, fs9, xplane
Q_PROPERTY(QString simulator READ getSimulator)
//! The _description_ property provides a short, human-readable description of the plugin.
Q_PROPERTY(QString description READ getDescription)
public: public:
//! Default constructor //! Default constructor
CSimulatorPluginInfo() = default; CSimulatorPluginInfo() = default;

View File

@@ -166,7 +166,7 @@ namespace BlackSimPlugin
return positionSlewMode; return positionSlewMode;
} }
HRESULT printDirectPlayError(HRESULT error) HRESULT logDirectPlayError(HRESULT error)
{ {
QString errorMessage; QString errorMessage;
switch(error) switch(error)
@@ -210,7 +210,6 @@ namespace BlackSimPlugin
errorMessage = "DirectPlay: " + errorMessage; errorMessage = "DirectPlay: " + errorMessage;
BlackMisc::CLogMessage("swift.fs9.freefunctions").error(errorMessage); BlackMisc::CLogMessage("swift.fs9.freefunctions").error(errorMessage);
return error; return error;
} }
} }

View File

@@ -61,7 +61,7 @@ namespace BlackSimPlugin
MPPositionSlewMode aircraftSituationToFS9(const BlackMisc::Aviation::CAircraftSituation &situation); MPPositionSlewMode aircraftSituationToFS9(const BlackMisc::Aviation::CAircraftSituation &situation);
//! Print the direct play error //! Print the direct play error
HRESULT printDirectPlayError(HRESULT error); HRESULT logDirectPlayError(HRESULT error);
} }
} }

View File

@@ -265,11 +265,11 @@ namespace BlackSimPlugin
CLSCTX_INPROC_SERVER, CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address, IID_IDirectPlay8Address,
reinterpret_cast<void **>(&m_deviceAddress)))) reinterpret_cast<void **>(&m_deviceAddress))))
return printDirectPlayError(hr); return logDirectPlayError(hr);
// Set the SP for our Device Address // Set the SP for our Device Address
if (FAILED(hr = m_deviceAddress->SetSP(&CLSID_DP8SP_TCPIP))) if (FAILED(hr = m_deviceAddress->SetSP(&CLSID_DP8SP_TCPIP)))
return printDirectPlayError(hr); return logDirectPlayError(hr);
return S_OK; return S_OK;
} }

View File

@@ -62,13 +62,13 @@ namespace BlackSimPlugin
IID_IDirectPlay8Address, IID_IDirectPlay8Address,
reinterpret_cast<void **>(&m_hostAddress)))) reinterpret_cast<void **>(&m_hostAddress))))
{ {
printDirectPlayError(hr); logDirectPlayError(hr);
return; return;
} }
if (FAILED(hr = m_hostAddress->BuildFromURLA(hostAddress.toLatin1().data()))) if (FAILED(hr = m_hostAddress->BuildFromURLA(hostAddress.toLatin1().data())))
{ {
printDirectPlayError(hr); logDirectPlayError(hr);
return; return;
} }
} }
@@ -132,7 +132,7 @@ namespace BlackSimPlugin
nullptr, // pAsyncHandle nullptr, // pAsyncHandle
DPNENUMHOSTS_SYNC))) // dwFlags DPNENUMHOSTS_SYNC))) // dwFlags
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
return hr; return hr;
} }
@@ -147,13 +147,13 @@ namespace BlackSimPlugin
IID_IDirectPlay8Address, IID_IDirectPlay8Address,
reinterpret_cast<void **>(&m_hostAddress)))) reinterpret_cast<void **>(&m_hostAddress))))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
// Set the SP for our Host Address // Set the SP for our Host Address
if (FAILED(hr = m_hostAddress->SetSP(&CLSID_DP8SP_TCPIP))) if (FAILED(hr = m_hostAddress->SetSP(&CLSID_DP8SP_TCPIP)))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
// FIXME: Test if this is also working via network or if we have to use the IP address // FIXME: Test if this is also working via network or if we have to use the IP address
@@ -164,7 +164,7 @@ namespace BlackSimPlugin
2 * (wcslen(hostname) + 1), /*bytes*/ 2 * (wcslen(hostname) + 1), /*bytes*/
DPNA_DATATYPE_STRING))) DPNA_DATATYPE_STRING)))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
return hr; return hr;
@@ -173,13 +173,11 @@ namespace BlackSimPlugin
HRESULT CFs9Client::connectToSession(const CCallsign &callsign) HRESULT CFs9Client::connectToSession(const CCallsign &callsign)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (m_clientStatus == Connected) { return hr; }
if (m_clientStatus == Connected) return hr;
QMutexLocker locker(&m_mutexHostList); QMutexLocker locker(&m_mutexHostList);
QScopedArrayPointer<wchar_t> wszPlayername(new wchar_t[callsign.toQString().size() + 1]); QScopedArrayPointer<wchar_t> wszPlayername(new wchar_t[callsign.toQString().size() + 1]);
callsign.toQString().toWCharArray(wszPlayername.data()); callsign.toQString().toWCharArray(wszPlayername.data());
wszPlayername[callsign.toQString().size()] = 0; wszPlayername[callsign.toQString().size()] = 0;
@@ -197,7 +195,7 @@ namespace BlackSimPlugin
m_player.pwszName = wszPlayername.data(); m_player.pwszName = wszPlayername.data();
if (FAILED(hr = m_directPlayPeer->SetPeerInfo(&m_player, nullptr, nullptr, DPNSETPEERINFO_SYNC))) if (FAILED(hr = m_directPlayPeer->SetPeerInfo(&m_player, nullptr, nullptr, DPNSETPEERINFO_SYNC)))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
// Now set up the Application Description // Now set up the Application Description
@@ -218,7 +216,7 @@ namespace BlackSimPlugin
nullptr, nullptr,
DPNCONNECT_SYNC))) DPNCONNECT_SYNC)))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
MPChangePlayerPlane mpChangePlayerPlane; MPChangePlayerPlane mpChangePlayerPlane;
@@ -246,12 +244,11 @@ namespace BlackSimPlugin
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
if (m_clientStatus == Disconnected) return hr; if (m_clientStatus == Disconnected) { return hr; }
BlackMisc::CLogMessage(this).debug() << "Closing DirectPlay connection for " << m_callsign; BlackMisc::CLogMessage(this).debug() << "Closing DirectPlay connection for " << m_callsign;
if (FAILED(hr = m_directPlayPeer->Close(0))) if (FAILED(hr = m_directPlayPeer->Close(0)))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
m_clientStatus = Disconnected; m_clientStatus = Disconnected;

View File

@@ -43,7 +43,7 @@ namespace BlackSimPlugin
ZeroMemory( addresses.data(), dwNumAddresses * sizeof(LPDIRECTPLAY8ADDRESS) ); ZeroMemory( addresses.data(), dwNumAddresses * sizeof(LPDIRECTPLAY8ADDRESS) );
if (FAILED (hr = m_directPlayPeer->GetLocalHostAddresses(addresses.data(), &dwNumAddresses, 0))) if (FAILED (hr = m_directPlayPeer->GetLocalHostAddresses(addresses.data(), &dwNumAddresses, 0)))
{ {
printDirectPlayError(hr); logDirectPlayError(hr);
return address; return address;
} }
@@ -121,7 +121,7 @@ namespace BlackSimPlugin
player.pwszName = wszPlayername.data(); player.pwszName = wszPlayername.data();
if (FAILED(hr = m_directPlayPeer->SetPeerInfo(&player, nullptr, nullptr, DPNSETPEERINFO_SYNC))) if (FAILED(hr = m_directPlayPeer->SetPeerInfo(&player, nullptr, nullptr, DPNSETPEERINFO_SYNC)))
{ {
printDirectPlayError(hr); logDirectPlayError(hr);
return hr; return hr;
} }
@@ -139,7 +139,7 @@ namespace BlackSimPlugin
nullptr, // Player Context nullptr, // Player Context
0))) // dwFlags 0))) // dwFlags
{ {
printDirectPlayError(hr); logDirectPlayError(hr);
return hr; return hr;
} }
else else
@@ -177,12 +177,12 @@ namespace BlackSimPlugin
BlackMisc::CLogMessage(this).info("Hosting terminated!"); BlackMisc::CLogMessage(this).info("Hosting terminated!");
if (FAILED(hr = m_directPlayPeer->TerminateSession(nullptr, 0, 0))) if (FAILED(hr = m_directPlayPeer->TerminateSession(nullptr, 0, 0)))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
if (FAILED(hr = m_directPlayPeer->Close(0))) if (FAILED(hr = m_directPlayPeer->Close(0)))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
m_hostStatus = Terminated; m_hostStatus = Terminated;

View File

@@ -64,14 +64,14 @@ namespace BlackSimPlugin
CLSCTX_INPROC_SERVER, CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Peer, IID_IDirectPlay8Peer,
(LPVOID *) &m_directPlayPeer))) (LPVOID *) &m_directPlayPeer)))
return printDirectPlayError(hr); return logDirectPlayError(hr);
// Turn off parameter validation in release builds // Turn off parameter validation in release builds
const DWORD dwInitFlags = 0; const DWORD dwInitFlags = 0;
// const DWORD dwInitFlags = DPNINITIALIZE_DISABLEPARAMVAL; // const DWORD dwInitFlags = DPNINITIALIZE_DISABLEPARAMVAL;
if (FAILED(hr = m_directPlayPeer->Initialize(&m_callbackWrapper, m_callbackWrapper.messageHandler, dwInitFlags))) if (FAILED(hr = m_directPlayPeer->Initialize(&m_callbackWrapper, m_callbackWrapper.messageHandler, dwInitFlags)))
return printDirectPlayError(hr); return logDirectPlayError(hr);
// Create and init IDirectPlay8LobbyClient // Create and init IDirectPlay8LobbyClient
@@ -79,10 +79,10 @@ namespace BlackSimPlugin
CLSCTX_INPROC_SERVER, CLSCTX_INPROC_SERVER,
IID_IDirectPlay8LobbyClient, IID_IDirectPlay8LobbyClient,
(LPVOID *) &m_dpLobbyClient))) (LPVOID *) &m_dpLobbyClient)))
return printDirectPlayError(hr); return logDirectPlayError(hr);
if (FAILED(hr = m_dpLobbyClient->Initialize(&m_lobbyCallbackWrapper, m_lobbyCallbackWrapper.messageHandler, dwInitFlags))) if (FAILED(hr = m_dpLobbyClient->Initialize(&m_lobbyCallbackWrapper, m_lobbyCallbackWrapper.messageHandler, dwInitFlags)))
return printDirectPlayError(hr); return logDirectPlayError(hr);
return S_OK; return S_OK;
} }
@@ -171,31 +171,31 @@ namespace BlackSimPlugin
if (FAILED(hr = CoCreateInstance(CLSID_DirectPlay8Address, nullptr, CLSCTX_INPROC_SERVER, if (FAILED(hr = CoCreateInstance(CLSID_DirectPlay8Address, nullptr, CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address, reinterpret_cast<void **>(&pHostAddress)))) IID_IDirectPlay8Address, reinterpret_cast<void **>(&pHostAddress))))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
// Set the SP to pHostAddress // Set the SP to pHostAddress
if (FAILED(hr = pHostAddress->SetSP(pSPGuid.data()))) if (FAILED(hr = pHostAddress->SetSP(pSPGuid.data())))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
// Create a device address to specify which device we are using // Create a device address to specify which device we are using
if (FAILED(hr = CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, if (FAILED(hr = CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address, reinterpret_cast<void **>(&pDeviceAddress)))) IID_IDirectPlay8Address, reinterpret_cast<void **>(&pDeviceAddress))))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
// Set the SP to pDeviceAddress // Set the SP to pDeviceAddress
if (FAILED(hr = pDeviceAddress->SetSP(&CLSID_DP8SP_TCPIP))) if (FAILED(hr = pDeviceAddress->SetSP(&CLSID_DP8SP_TCPIP)))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
if (FAILED(hr = pHostAddress->BuildFromURLA(address.toLocal8Bit().data()))) if (FAILED(hr = pHostAddress->BuildFromURLA(address.toLocal8Bit().data())))
{ {
return printDirectPlayError(hr); return logDirectPlayError(hr);
} }
// Setup the DPL_CONNECTION_SETTINGS // Setup the DPL_CONNECTION_SETTINGS

View File

@@ -74,6 +74,7 @@ namespace BlackSimPlugin
bool CSimulatorFs9::connectTo() bool CSimulatorFs9::connectTo()
{ {
Q_ASSERT_X(fs9Host, Q_FUNC_INFO, "No FS9 host");
if (!fs9Host->isConnected()) { return false; } // host not available, we quit if (!fs9Host->isConnected()) { return false; } // host not available, we quit
Q_ASSERT_X(m_fsuipc, Q_FUNC_INFO, "No FSUIPC"); Q_ASSERT_X(m_fsuipc, Q_FUNC_INFO, "No FSUIPC");
@@ -327,21 +328,20 @@ namespace BlackSimPlugin
return exclude; return exclude;
} }
CSimulatorFs9Listener::CSimulatorFs9Listener(const CSimulatorPluginInfo &info, QObject *parent) : CSimulatorFs9Listener::CSimulatorFs9Listener(const CSimulatorPluginInfo &info) :
BlackCore::ISimulatorListener(info, parent), BlackCore::ISimulatorListener(info),
m_timer(new QTimer(this)) m_timer(new QTimer(this))
{ {
Q_CONSTEXPR int QueryInterval = 5 * 1000; // 5 seconds const int QueryInterval = 5 * 1000; // 5 seconds
m_timer->setInterval(QueryInterval); m_timer->setInterval(QueryInterval);
m_timer->setObjectName(this->objectName() + ":m_timer");
// Test whether we can lobby connect at all. // Test whether we can lobby connect at all.
bool canLobbyConnect = lobbyClient->canLobbyConnect(); bool canLobbyConnect = lobbyClient->canLobbyConnect();
connect(m_timer, &QTimer::timeout, [this, canLobbyConnect]() connect(m_timer, &QTimer::timeout, [this, canLobbyConnect]()
{ {
if (fs9Host->getHostAddress().isEmpty()) // host not yet set up if (fs9Host->getHostAddress().isEmpty()) { return; } // host not yet set up
return;
if (canLobbyConnect) if (canLobbyConnect)
{ {
if (m_isConnecting || lobbyClient->connectFs9ToHost(fs9Host->getHostAddress()) == S_OK) if (m_isConnecting || lobbyClient->connectFs9ToHost(fs9Host->getHostAddress()) == S_OK)
@@ -402,9 +402,9 @@ namespace BlackSimPlugin
return new CSimulatorFs9(info, ownAircraftProvider, remoteAircraftProvider, pluginStorageProvider, this); return new CSimulatorFs9(info, ownAircraftProvider, remoteAircraftProvider, pluginStorageProvider, this);
} }
BlackCore::ISimulatorListener *CSimulatorFs9Factory::createListener(const CSimulatorPluginInfo &info, QObject *parent) BlackCore::ISimulatorListener *CSimulatorFs9Factory::createListener(const CSimulatorPluginInfo &info)
{ {
return new CSimulatorFs9Listener(info, parent); return new CSimulatorFs9Listener(info);
} }
} // namespace } // namespace

View File

@@ -128,7 +128,7 @@ namespace BlackSimPlugin
public: public:
//! Constructor //! Constructor
CSimulatorFs9Listener(const BlackMisc::Simulation::CSimulatorPluginInfo &info, QObject *parent); CSimulatorFs9Listener(const BlackMisc::Simulation::CSimulatorPluginInfo &info);
public slots: public slots:
//! \copydoc BlackCore::ISimulatorListener::start //! \copydoc BlackCore::ISimulatorListener::start
@@ -167,7 +167,7 @@ namespace BlackSimPlugin
BlackMisc::IPluginStorageProvider *pluginStorageProvider) override; BlackMisc::IPluginStorageProvider *pluginStorageProvider) override;
//! \copydoc BlackCore::ISimulatorFactory::createListener //! \copydoc BlackCore::ISimulatorFactory::createListener
virtual BlackCore::ISimulatorListener *createListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info, QObject *parent = nullptr) override; virtual BlackCore::ISimulatorListener *createListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info) override;
}; };
} // namespace Fs9 } // namespace Fs9

View File

@@ -79,19 +79,23 @@ namespace BlackSimPlugin
bool CSimulatorFsx::connectTo() bool CSimulatorFsx::connectTo()
{ {
connect(&m_watcherConnect, SIGNAL(finished()), this, SLOT(ps_connectToFinished())); if (this->isConnected()) { return true; }
if (FAILED(SimConnect_Open(&m_hSimConnect, BlackMisc::CProject::systemNameAndVersionChar(), nullptr, 0, 0, 0)))
// simplified connect, timers and signals not in different thread
auto asyncConnectFunc = [&]() -> bool
{ {
if (FAILED(SimConnect_Open(&m_hSimConnect, BlackMisc::CProject::systemNameAndVersionChar(), nullptr, 0, 0, 0))) { return false; } // reset state as expected for unconnected
if (m_simconnectTimerId >= 0) { killTimer(m_simconnectTimerId); }
m_simConnected = false;
m_simSimulating = false;
return false;
}
if (m_useFsuipc) { this->m_fsuipc->connect(); } // FSUIPC too if (m_useFsuipc) { this->m_fsuipc->connect(); } // FSUIPC too
return true;
};
QFuture<bool> result = QtConcurrent::run(asyncConnectFunc);
m_watcherConnect.setFuture(result);
// set structures and move on
initEvents();
initDataDefinitionsWhenConnected();
m_simconnectTimerId = startTimer(10);
m_simConnected = true;
emitSimulatorCombinedStatus();
return true; return true;
} }
@@ -500,25 +504,6 @@ namespace BlackSimPlugin
} }
} }
void CSimulatorFsx::ps_connectToFinished()
{
if (m_watcherConnect.result())
{
initEvents();
initDataDefinitionsWhenConnected();
m_simconnectTimerId = startTimer(10);
m_simConnected = true;
emitSimulatorCombinedStatus();
}
else
{
if (m_simconnectTimerId >= 0) { killTimer(m_simconnectTimerId); }
m_simConnected = false;
m_simSimulating = false;
emitSimulatorCombinedStatus();
}
}
bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CCallsign &callsign) bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CCallsign &callsign)
{ {
// only remove from sim // only remove from sim
@@ -860,22 +845,14 @@ namespace BlackSimPlugin
return exclude; return exclude;
} }
CSimulatorFsxListener::CSimulatorFsxListener(const CSimulatorPluginInfo &info, QObject *parent) : CSimulatorFsxListener::CSimulatorFsxListener(const CSimulatorPluginInfo &info) :
ISimulatorListener(info, parent), ISimulatorListener(info),
m_timer(new QTimer(this)) m_timer(new QTimer(this))
{ {
Q_CONSTEXPR int QueryInterval = 5 * 1000; // 5 seconds Q_CONSTEXPR int QueryInterval = 5 * 1000; // 5 seconds
m_timer->setInterval(QueryInterval); m_timer->setInterval(QueryInterval);
this->setObjectName("CSimulatorFsxListener");
this->m_timer->setObjectName(this->objectName().append(":m_timer")); this->m_timer->setObjectName(this->objectName().append(":m_timer"));
connect(m_timer, &QTimer::timeout, this, &CSimulatorFsxListener::ps_checkConnection);
connect(m_timer, &QTimer::timeout, [this]()
{
HANDLE hSimConnect;
HRESULT result = SimConnect_Open(&hSimConnect, BlackMisc::CProject::systemNameAndVersionChar(), nullptr, 0, 0, 0);
SimConnect_Close(hSimConnect);
if (result == S_OK) { emit simulatorStarted(this->getPluginInfo()); }
});
} }
void CSimulatorFsxListener::start() void CSimulatorFsxListener::start()
@@ -888,5 +865,17 @@ namespace BlackSimPlugin
m_timer->stop(); m_timer->stop();
} }
void CSimulatorFsxListener::ps_checkConnection()
{
Q_ASSERT_X(!BlackCore::isCurrentThreadApplicationThread(), Q_FUNC_INFO, "Expect to run in background");
HANDLE hSimConnect;
HRESULT result = SimConnect_Open(&hSimConnect, BlackMisc::CProject::systemNameAndVersionChar(), nullptr, 0, 0, 0);
SimConnect_Close(hSimConnect);
if (result == S_OK)
{
emit simulatorStarted(this->getPluginInfo());
}
}
} // namespace } // namespace
} // namespace } // namespace

View File

@@ -141,9 +141,6 @@ namespace BlackSimPlugin
//! Dispatch SimConnect messages //! Dispatch SimConnect messages
void ps_dispatch(); void ps_dispatch();
//! Called when asynchronous connection to Simconnect has finished
void ps_connectToFinished();
private: private:
//! Called when sim has started //! Called when sim has started
void onSimRunning(); void onSimRunning();
@@ -202,7 +199,6 @@ namespace BlackSimPlugin
int m_dispatchErrors = 0; //!< numer of dispatched failed, \sa ps_dispatch int m_dispatchErrors = 0; //!< numer of dispatched failed, \sa ps_dispatch
HANDLE m_hSimConnect = nullptr; //!< Handle to SimConnect object HANDLE m_hSimConnect = nullptr; //!< Handle to SimConnect object
QHash<BlackMisc::Aviation::CCallsign, CSimConnectObject> m_simConnectObjects; QHash<BlackMisc::Aviation::CCallsign, CSimConnectObject> m_simConnectObjects;
QFutureWatcher<bool> m_watcherConnect;
// statistics // statistics
qint64 m_statsUpdateAircraftTimeTotal = 0; qint64 m_statsUpdateAircraftTimeTotal = 0;
@@ -217,7 +213,7 @@ namespace BlackSimPlugin
public: public:
//! Constructor //! Constructor
CSimulatorFsxListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info, QObject *parent); CSimulatorFsxListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info);
public slots: public slots:
//! \copydoc BlackCore::ISimulatorListener::start //! \copydoc BlackCore::ISimulatorListener::start
@@ -226,6 +222,10 @@ namespace BlackSimPlugin
//! \copydoc BlackCore::ISimulatorListener::stop //! \copydoc BlackCore::ISimulatorListener::stop
virtual void stop() override; virtual void stop() override;
private slots:
//! Test if connection can be established
void ps_checkConnection();
private: private:
QTimer *m_timer { nullptr }; QTimer *m_timer { nullptr };
}; };

View File

@@ -27,9 +27,9 @@ namespace BlackSimPlugin
return new CSimulatorFsx(info, ownAircraftProvider, renderedAircraftProvider, pluginStorageProvider, this); return new CSimulatorFsx(info, ownAircraftProvider, renderedAircraftProvider, pluginStorageProvider, this);
} }
BlackCore::ISimulatorListener *CSimulatorFsxFactory::createListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info, QObject *parent) BlackCore::ISimulatorListener *CSimulatorFsxFactory::createListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info)
{ {
return new CSimulatorFsxListener(info, parent); return new CSimulatorFsxListener(info);
} }
} // namespace } // namespace

View File

@@ -40,7 +40,7 @@ namespace BlackSimPlugin
BlackMisc::IPluginStorageProvider *pluginStorageProvider) override; BlackMisc::IPluginStorageProvider *pluginStorageProvider) override;
//! \copydoc BlackCore::ISimulatorFactory::getListener //! \copydoc BlackCore::ISimulatorFactory::getListener
virtual BlackCore::ISimulatorListener *createListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info, QObject *parent = nullptr) override; virtual BlackCore::ISimulatorListener *createListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info) override;
}; };
} // namespace } // namespace

View File

@@ -158,12 +158,7 @@ namespace BlackSimPlugin
bool CSimulatorXPlane::connectTo() bool CSimulatorXPlane::connectTo()
{ {
if (isConnected()) if (isConnected()) { return true; }
{
qWarning("X-Plane already connected");
return true;
}
m_conn = QDBusConnection::sessionBus(); // TODO make this configurable m_conn = QDBusConnection::sessionBus(); // TODO make this configurable
m_service = new CXBusServiceProxy(m_conn, this); m_service = new CXBusServiceProxy(m_conn, this);
m_traffic = new CXBusTrafficProxy(m_conn, this); m_traffic = new CXBusTrafficProxy(m_conn, this);
@@ -438,7 +433,7 @@ namespace BlackSimPlugin
return new CSimulatorXPlane(info, ownAircraftProvider, renderedAircraftProvider, pluginStorageProvider, this); return new CSimulatorXPlane(info, ownAircraftProvider, renderedAircraftProvider, pluginStorageProvider, this);
} }
CSimulatorXPlaneListener::CSimulatorXPlaneListener(const CSimulatorPluginInfo &info, QObject *parent): ISimulatorListener(info, parent) CSimulatorXPlaneListener::CSimulatorXPlaneListener(const CSimulatorPluginInfo &info): ISimulatorListener(info)
{ } { }
void CSimulatorXPlaneListener::start() void CSimulatorXPlaneListener::start()

View File

@@ -186,7 +186,7 @@ namespace BlackSimPlugin
public: public:
//! Constructor //! Constructor
CSimulatorXPlaneListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info, QObject *parent); CSimulatorXPlaneListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info);
public slots: public slots:
//! \copydoc BlackCore::ISimulatorListener::start //! \copydoc BlackCore::ISimulatorListener::start
@@ -222,7 +222,7 @@ namespace BlackSimPlugin
BlackMisc::IPluginStorageProvider *pluginStorageProvider) override; BlackMisc::IPluginStorageProvider *pluginStorageProvider) override;
//! \copydoc BlackCore::ISimulatorFactory::createListener //! \copydoc BlackCore::ISimulatorFactory::createListener
virtual BlackCore::ISimulatorListener *createListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info, QObject *parent = nullptr) override { return new CSimulatorXPlaneListener(info, parent); } virtual BlackCore::ISimulatorListener *createListener(const BlackMisc::Simulation::CSimulatorPluginInfo &info) override { return new CSimulatorXPlaneListener(info); }
}; };
} // ns } // ns