diff --git a/src/blackcore/context_simulator_impl.cpp b/src/blackcore/context_simulator_impl.cpp index 54e0a145b..7b272541f 100644 --- a/src/blackcore/context_simulator_impl.cpp +++ b/src/blackcore/context_simulator_impl.cpp @@ -60,7 +60,7 @@ namespace BlackCore if (factory) { driver.factory = factory; - CLogMessage(this).info("Loaded plugin: %1") << factory->getSimulatorInfo().toQString(); + CLogMessage(this).debug() << "Loaded plugin: " << plugin->info.toQString(); } } else { QString errorMsg = loader.errorString().append(" ").append("Also check if required dll/libs of plugin exists"); @@ -342,14 +342,14 @@ namespace BlackCore asyncConnectToSimulator(); // info about what is going on - CLogMessage(this).info("Simulator plugin loaded: '%1'") << this->m_simulator->getSimulatorInfo().toQString(true); + CLogMessage(this).info("Simulator plugin loaded: %1") << this->m_simulator->getSimulatorInfo().toQString(true); return true; } bool CContextSimulator::loadSimulatorPluginFromSettings() { Q_ASSERT(this->getIContextSettings()); - if (!this->getIContextSettings()) { return false; } + if (!this->getIContextSettings()) return false; // TODO assert or if? // TODO warnings if we didn't load the plugin which the settings asked for @@ -409,7 +409,7 @@ namespace BlackCore ISimulatorListener *listener = m_simulatorDrivers[simulatorInfo].listener; Q_ASSERT(listener); listener->start(); - CLogMessage(this).info("Listening for simulator: '%1'") << simulatorInfo.toQString(true); + CLogMessage(this).debug() << "Listening for simulator:" << simulatorInfo.toQString(true); } @@ -433,19 +433,25 @@ namespace BlackCore void CContextSimulator::unloadSimulatorPlugin() { - if (this->m_simulator) - { + if (m_simulator) { // depending on shutdown order, network might already have been deleted IContextNetwork *networkContext = this->getIContextNetwork(); Q_ASSERT(networkContext); Q_ASSERT(networkContext->isLocalObject()); Q_UNUSED(networkContext); - this->m_simulator->disconnect(); // disconnect all simulator signals - QObject::disconnect(this, nullptr, this->m_simulator, nullptr); // disconnect receiver simulator - this->m_simulator->disconnectFrom(); // disconnect from simulator - this->m_simulator->deleteLater(); + Q_ASSERT(m_simulator->simulator); + + m_simulator->simulator->disconnect(); + CLogHandler::instance()->disconnect(m_simulator->simulator); + this->disconnect(m_simulator->simulator); + + if (m_simulator->simulator->isConnected()) + m_simulator->simulator->disconnectFrom(); // disconnect from simulator + + m_simulator->simulator->deleteLater(); + m_simulator->simulator = nullptr; + m_simulator = nullptr; } - this->m_simulator = nullptr; } void CContextSimulator::ps_addRemoteAircraft(const CSimulatedAircraft &remoteAircraft) @@ -479,6 +485,7 @@ namespace BlackCore void CContextSimulator::ps_textMessagesReceived(const Network::CTextMessageList &textMessages) { + Q_ASSERT(this->m_simulator); // TODO Assert or if? if (!this->m_simulator) { return; } foreach(CTextMessage tm, textMessages) { @@ -511,7 +518,7 @@ namespace BlackCore void CContextSimulator::ps_updateSimulatorCockpitFromContext(const CAircraft &ownAircraft, const QString &originator) { - Q_ASSERT(this->m_simulator); + Q_ASSERT(this->m_simulator); // TODO Assert or if? if (!this->m_simulator) { return; } // avoid loops @@ -583,7 +590,7 @@ namespace BlackCore void CContextSimulator::ps_simulatorStarted(CSimulatorInfo simulatorInfo) { - CLogMessage(this).info("Simulator %1 started.") << simulatorInfo.toQString(); + CLogMessage(this).debug() << simulatorInfo.toQString() << "started"; stopSimulatorListeners(); loadSimulatorPlugin(simulatorInfo); } @@ -605,15 +612,19 @@ namespace BlackCore continue; } - CLogMessage(this).info("Try to load plugin: %1") << fileName; + CLogMessage(this).debug() << "Try to load plugin: " << fileName; QString pluginPath = m_pluginsDir.absoluteFilePath(fileName); QPluginLoader loader(pluginPath); QJsonObject json = loader.metaData(); CSimulatorInfo simulatorInfo(json); - if (!simulatorInfo.isUnspecified()) { + if (!simulatorInfo.isUnspecified()) + { m_simulatorDrivers.insert(simulatorInfo, { nullptr, nullptr, pluginPath} ); - CLogMessage(this).info("Found simulator driver: %1") << simulatorInfo.toQString(); - } else { + CLogMessage(this).debug() << "Found simulator driver: " << simulatorInfo.toQString(); + } + else + { + CLogMessage(this).warning("Simulator driver in %1 is invalid") << pluginPath; } } diff --git a/src/plugins/simulator/fs9/directplay_peer.cpp b/src/plugins/simulator/fs9/directplay_peer.cpp index c31919bc1..fd9ceb5df 100644 --- a/src/plugins/simulator/fs9/directplay_peer.cpp +++ b/src/plugins/simulator/fs9/directplay_peer.cpp @@ -291,8 +291,14 @@ namespace BlackSimPlugin DPNSEND_SYNC | DPNSEND_NOLOOPBACK))) { CLogMessage(this).warning("DirectPlay: Failed to send message!"); + qDebug() << message; } return hr; } + + void CDirectPlayPeer::reset() + { + m_playerUser = 0; + } } } diff --git a/src/plugins/simulator/fs9/directplay_peer.h b/src/plugins/simulator/fs9/directplay_peer.h index bbc95e450..bd8938a08 100644 --- a/src/plugins/simulator/fs9/directplay_peer.h +++ b/src/plugins/simulator/fs9/directplay_peer.h @@ -48,6 +48,8 @@ namespace BlackSimPlugin //! Send a custom DirectPlay message HRESULT sendMessage(const QByteArray &data); + void reset(); + signals: //! Received custom FS9 packet void customPacketReceived(const QByteArray &data); diff --git a/src/plugins/simulator/fs9/fs9_host.cpp b/src/plugins/simulator/fs9/fs9_host.cpp index 824ef7c1e..d3364f652 100644 --- a/src/plugins/simulator/fs9/fs9_host.cpp +++ b/src/plugins/simulator/fs9/fs9_host.cpp @@ -72,6 +72,7 @@ namespace BlackSimPlugin MultiPlayerPacketParser::writeType(message, CFs9Sdk::MPCHAT_PACKET_ID_CHAT_TEXT_SEND); MultiPlayerPacketParser::writeSize(message, mpChatText.chat_data.size() + 1); message = MultiPlayerPacketParser::writeMessage(message, mpChatText); + qDebug() << "Message:" << textMessage; sendMessage(message); } @@ -87,7 +88,6 @@ namespace BlackSimPlugin stopHosting(); } - HRESULT CFs9Host::startHosting(const QString &session, const QString &callsign) { HRESULT hr = S_OK; diff --git a/src/plugins/simulator/fs9/lobby_client.cpp b/src/plugins/simulator/fs9/lobby_client.cpp index c66f8c0c8..0a764e2eb 100644 --- a/src/plugins/simulator/fs9/lobby_client.cpp +++ b/src/plugins/simulator/fs9/lobby_client.cpp @@ -92,9 +92,6 @@ namespace BlackSimPlugin GUID pAppGuid = CFs9Sdk::guid(); - // Set to true in order to automatically launch FS9. Perfect for testing. - bool bLaunchNotFound = false; - // Setup the DPL_CONNECT_INFO struct DPL_CONNECT_INFO dnConnectInfo; ZeroMemory(&dnConnectInfo, sizeof(DPL_CONNECT_INFO)); @@ -102,7 +99,6 @@ namespace BlackSimPlugin dnConnectInfo.pvLobbyConnectData = nullptr; dnConnectInfo.dwLobbyConnectDataSize = 0; dnConnectInfo.dwFlags = 0; - if (bLaunchNotFound) dnConnectInfo.dwFlags |= DPLCONNECT_LAUNCHNOTFOUND; dnConnectInfo.guidApplication = pAppGuid; if (FAILED(hr = allocAndInitConnectSettings(address, &pAppGuid, &dnConnectInfo.pdplConnectionSettings))) @@ -113,21 +109,18 @@ namespace BlackSimPlugin &m_applicationHandle, INFINITE, 0); - if (FAILED(hr)) - { - if (hr == DPNERR_NOCONNECTION && !bLaunchNotFound) - qWarning() << "There were no waiting application."; - else - return printDirectPlayError(hr); - } - else - { + if (FAILED(hr)) { + return hr == DPNERR_NOCONNECTION ? S_FALSE : printDirectPlayError(hr); + } else { qDebug() << "Connected!"; + freeConnectSettings(dnConnectInfo.pdplConnectionSettings); + return S_OK; } + } - freeConnectSettings(dnConnectInfo.pdplConnectionSettings); + void CLobbyClient::cleanup() + { - return S_OK; } HRESULT CLobbyClient::allocAndInitConnectSettings(const QString &address, GUID *pAppGuid, DPL_CONNECTION_SETTINGS **ppdplConnectSettings) @@ -247,7 +240,9 @@ namespace BlackSimPlugin { PDPL_MESSAGE_DISCONNECT pDisconnectMsg; pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)msgBuffer; - Q_UNUSED(pDisconnectMsg) + Q_UNUSED(pDisconnectMsg); + + emit disconnected(); // We should free any data associated with the // app here, but there is none. diff --git a/src/plugins/simulator/fs9/lobby_client.h b/src/plugins/simulator/fs9/lobby_client.h index 27c1465e2..6a5a416ff 100644 --- a/src/plugins/simulator/fs9/lobby_client.h +++ b/src/plugins/simulator/fs9/lobby_client.h @@ -13,6 +13,10 @@ namespace BlackSimPlugin { Q_OBJECT + signals: + //! Emitted when FS9 is closed + void disconnected(); + public: //! Constructor @@ -27,6 +31,9 @@ namespace BlackSimPlugin //! Connect FS9 simulator to our host HRESULT connectFs9ToHost(const QString address); + //! Cleanup & be ready to another connection + void cleanup(); + private: //! Alloc and fill up a DPL_CONNECTION_SETTINGS. Call FreeConnectSettings later to free it. diff --git a/src/plugins/simulator/fs9/simulator_fs9.cpp b/src/plugins/simulator/fs9/simulator_fs9.cpp index 087a82de5..3222c2f9f 100644 --- a/src/plugins/simulator/fs9/simulator_fs9.cpp +++ b/src/plugins/simulator/fs9/simulator_fs9.cpp @@ -16,6 +16,7 @@ #include "multiplayer_packet_parser.h" #include "blackcore/interpolator_linear.h" #include "blacksim/simulatorinfo.h" +#include "blackmisc/logmessage.h" #include "blackmisc/project.h" #include "blackmisc/logmessage.h" #include "blackmisc/propertyindexallclasses.h" @@ -37,36 +38,49 @@ namespace BlackSimPlugin { namespace Fs9 { + CSimulatorFs9Factory::CSimulatorFs9Factory(QObject *parent) : + QObject(parent), + m_fs9Host(new CFs9Host(this), [](CFs9Host* host){ + host->quit(); + host->deleteLater(); + }), + m_lobbyClient(new CLobbyClient(this)) + { + registerMetadata(); + } + BlackCore::ISimulator *CSimulatorFs9Factory::create( IOwnAircraftProvider *ownAircraftProvider, IRemoteAircraftProvider *remoteAircraftProvider, QObject *parent) { - registerMetadata(); return new Fs9::CSimulatorFs9(ownAircraftProvider, remoteAircraftProvider, parent); } + + BlackCore::ISimulatorListener *CSimulatorFs9Factory::createListener(QObject *parent) + { + return new CSimulatorFs9Listener(m_fs9Host, m_lobbyClient, parent); + } BlackSim::CSimulatorInfo CSimulatorFs9Factory::getSimulatorInfo() const { return CSimulatorInfo::FS9(); } - CSimulatorFs9::CSimulatorFs9(IOwnAircraftProvider *ownAircraftProvider, IRemoteAircraftProvider *remoteAircraftProvider, QObject *parent) : - CSimulatorFsCommon(CSimulatorInfo::FS9(), ownAircraftProvider, remoteAircraftProvider, parent), - m_fs9Host(new CFs9Host(this)), m_lobbyClient(new CLobbyClient(this)) + CSimulatorFs9::CSimulatorFs9(IOwnAircraftProvider *ownAircraftProvider, + IRemoteAircraftProvider *remoteAircraftProvider, + const QSharedPointer &fs9Host, + const QSharedPointer &lobbyClient, QObject *parent) : + CSimulatorFsCommon(CSimulatorInfo::FS9(), ownAircraftProvider, remoteAircraftProvider, parent), + m_fs9Host(new CFs9Host(this)), + m_lobbyClient(new CLobbyClient(this)) { + connect(m_lobbyClient.data(), &CLobbyClient::disconnected, this, std::bind(&CSimulatorFs9::simulatorStatusChanged, this, 0)); connect(m_fs9Host.data(), &CFs9Host::customPacketReceived, this, &CSimulatorFs9::ps_processFs9Message); - connect(m_fs9Host.data(), &CFs9Host::statusChanged, this, &CSimulatorFs9::ps_changeHostStatus); - m_fs9Host->start(); this->m_interpolator = new BlackCore::CInterpolatorLinear(remoteAircraftProvider, this); this->m_interpolator->start(); } - CSimulatorFs9::~CSimulatorFs9() - { - Q_ASSERT(!m_isHosting); - } - bool CSimulatorFs9::isConnected() const { return m_fs9Host->isConnected(); @@ -74,19 +88,11 @@ namespace BlackSimPlugin bool CSimulatorFs9::connectTo() { - Q_ASSERT(m_fsuipc); - if (m_useFsuipc) { m_fsuipc->connect(); } // connect FSUIPC too + Q_ASSERT(m_fs9Host->isConnected()); + m_fsuipc->connect(); // connect FSUIPC too + startTimer(50); + emitSimulatorCombinedStatus(); - // If we are already hosting, connect FS0 through lobby connection - if (m_isHosting) - { - m_lobbyClient->connectFs9ToHost(m_fs9Host->getHostAddress()); - } - // If not, deferre connection until host is setup - else - { - m_startedLobbyConnection = true; - } return true; } @@ -99,11 +105,7 @@ namespace BlackSimPlugin bool CSimulatorFs9::disconnectFrom() { disconnectAllClients(); - - emit connectionStatusChanged(ISimulator::Disconnected); - if (m_fs9Host) { m_fs9Host->quit(); } - CSimulatorFsCommon::disconnectFrom(); - m_isHosting = false; + m_fsuipc->disconnect(); return true; } @@ -199,12 +201,13 @@ namespace BlackSimPlugin void CSimulatorFs9::displayStatusMessage(const BlackMisc::CStatusMessage &message) const { + /* Avoid errors from CDirectPlayPeer as it may end in infinite loop */ + if (message.getSeverity() == BlackMisc::CStatusMessage::SeverityError && message.isFromClass()) + return; + if (message.getSeverity() != BlackMisc::CStatusMessage::SeverityDebug) { - if (m_fs9Host) - { - QMetaObject::invokeMethod(m_fs9Host, "sendTextMessage", Q_ARG(QString, message.toQString())); - } + QMetaObject::invokeMethod(m_fs9Host.data(), "sendTextMessage", Q_ARG(QString, message.toQString())); } } @@ -272,34 +275,7 @@ namespace BlackSimPlugin } } - void CSimulatorFs9::ps_changeHostStatus(BlackSimPlugin::Fs9::CFs9Host::HostStatus status) - { - switch (status) - { - case CFs9Host::Hosting: - { - m_isHosting = true; - startTimer(50); - emit connectionStatusChanged(Connected); - if (m_startedLobbyConnection) - { - m_lobbyClient->connectFs9ToHost(m_fs9Host->getHostAddress()); - m_startedLobbyConnection = false; - } - break; - } - case CFs9Host::Terminated: - { - m_isHosting = false; - emit connectionStatusChanged(Disconnected); - break; - } - default: - break; - } - } - - void CSimulatorFs9::updateOwnAircraftFromSimulator(const CAircraft &simDataOwnAircraft) + void CSimulatorFs9::updateOwnAircraftFromSim(const CAircraft &ownAircraft) { this->providerUpdateCockpit( simDataOwnAircraft.getCom1System(), @@ -316,5 +292,48 @@ namespace BlackSimPlugin removeRemoteAircraft(fs9Client); } } - } // namespace -} // namespace + + CSimulatorFs9Listener::CSimulatorFs9Listener(const QSharedPointer &fs9Host, + const QSharedPointer &lobbyClient, + QObject *parent) : + BlackCore::ISimulatorListener(parent), + m_timer(new QTimer(this)), + m_fs9Host(fs9Host), + m_lobbyClient(lobbyClient) + { + Q_CONSTEXPR int QueryInterval = 5 * 1000; // 5 seconds + m_timer->setInterval(QueryInterval); + + connect(m_timer, &QTimer::timeout, [this]() + { + if (m_fs9Host->getHostAddress().isEmpty()) // host not yet set up + return; + + if (m_lobbyConnected || m_lobbyClient->connectFs9ToHost(m_fs9Host->getHostAddress()) == S_OK) { + m_lobbyConnected = true; + CLogMessage(this).info("Swift is joining FS9 to the multiplayer session..."); + } + + if (m_lobbyConnected && m_fs9Host->isConnected()) { + emit simulatorStarted(m_simulatorInfo); + m_lobbyConnected = false; + } + }); + + m_fs9Host->start(); + + // After FS9 is disconnected, reset its data stored in the host + connect(m_lobbyClient.data(), &CLobbyClient::disconnected, m_fs9Host.data(), &CFs9Host::reset); + } + + void CSimulatorFs9Listener::start() + { + m_timer->start(); + } + + void CSimulatorFs9Listener::stop() + { + m_timer->stop(); + } + } +} diff --git a/src/plugins/simulator/fs9/simulator_fs9.h b/src/plugins/simulator/fs9/simulator_fs9.h index c9e2b914f..f6de3cc97 100644 --- a/src/plugins/simulator/fs9/simulator_fs9.h +++ b/src/plugins/simulator/fs9/simulator_fs9.h @@ -32,24 +32,6 @@ namespace BlackSimPlugin { namespace Fs9 { - //! Factory implementation to create CSimulatorFs9 instances - class CSimulatorFs9Factory : public QObject, public BlackCore::ISimulatorFactory - { - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.swift.pilotclient.BlackCore.SimulatorInterface" FILE "simulator_fs9.json") - Q_INTERFACES(BlackCore::ISimulatorFactory) - - public: - //! \copydoc BlackCore::ISimulatorFactory::create(ownAircraftProvider, remoteAircraftProvider, parent) - virtual BlackCore::ISimulator *create( - BlackMisc::Simulation::IOwnAircraftProvider *ownAircraftProvider, - BlackMisc::Simulation::IRemoteAircraftProvider *remoteAircraftProvider, - QObject *parent) override; - - //! Simulator info - virtual BlackSim::CSimulatorInfo getSimulatorInfo() const override; - }; - //! FSX Simulator Implementation class CSimulatorFs9 : public BlackSimPlugin::FsCommon::CSimulatorFsCommon { @@ -63,7 +45,7 @@ namespace BlackSimPlugin QObject *parent = nullptr); //! Destructor - virtual ~CSimulatorFs9(); + virtual ~CSimulatorFs9() = default; //! \copydoc ISimulator::isConnected() virtual bool isConnected() const override; @@ -116,9 +98,6 @@ namespace BlackSimPlugin //! Process incoming FS9 message void ps_processFs9Message(const QByteArray &message); - //! Change DirectPlay host status - void ps_changeHostStatus(BlackSimPlugin::Fs9::CFs9Host::HostStatus status); - private: //! Called when data about our own aircraft are received @@ -126,14 +105,63 @@ namespace BlackSimPlugin void disconnectAllClients(); - // DirectPlay object handling - QPointer m_fs9Host; - bool m_isHosting = false; //!< Is sim connected? - bool m_startedLobbyConnection = false; + QSharedPointer m_fs9Host; QHash> m_hashFs9Clients; - CLobbyClient *m_lobbyClient; + QSharedPointer m_lobbyClient; }; - } // namespace -} // namespace + + //! Listener for FS9 + //! Listener starts the FS9 multiplayer host and tries to make the running instance + //! of simulator to connect to it. When emitting the simulatorStarted() signal, + //! FS9 is already connected. + class CSimulatorFs9Listener : public BlackCore::ISimulatorListener { + Q_OBJECT + + public: + //! Constructor + CSimulatorFs9Listener(const QSharedPointer &fs9Host, const QSharedPointer &lobbyClient, QObject* parent); + + //! \copydoc BlackCore::ISimulatorListener::start + virtual void start() override; + + //! \copydoc BlackCore::ISimulatorListener::stop + virtual void stop() override; + + private: + + QTimer* m_timer = nullptr; + QSharedPointer m_fs9Host; + QSharedPointer m_lobbyClient; + bool m_lobbyConnected = false; + const BlackSim::CSimulatorInfo m_simulatorInfo = BlackSim::CSimulatorInfo::FS9(); + + }; + + //! Factory implementation to create CSimulatorFs9 instances + class CSimulatorFs9Factory : public QObject, public BlackCore::ISimulatorFactory + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.swift.pilotclient.BlackCore.SimulatorInterface" FILE "simulator_fs9.json") + Q_INTERFACES(BlackCore::ISimulatorFactory) + + public: + CSimulatorFs9Factory(QObject* parent = nullptr); + + //! \copydoc BlackCore::ISimulatorFactory::create() + virtual BlackCore::ISimulator *create(QObject *parent) override; + + //! Simulator info + virtual BlackSim::CSimulatorInfo getSimulatorInfo() const override; + + //! \copydoc BlackCore::ISimulatorFactory::getListener + virtual BlackCore::ISimulatorListener *createListener(QObject *parent = nullptr) override; + + private: + QSharedPointer m_fs9Host; + QSharedPointer m_lobbyClient; + + }; + } // namespace Fs9 +} // namespace BlackCore #endif // guard diff --git a/src/plugins/simulator/fscommon/fsuipc.h b/src/plugins/simulator/fscommon/fsuipc.h index 914932baa..350bc1356 100644 --- a/src/plugins/simulator/fscommon/fsuipc.h +++ b/src/plugins/simulator/fscommon/fsuipc.h @@ -54,6 +54,9 @@ namespace BlackSimPlugin //! bool read(BlackMisc::Simulation::CSimulatedAircraft &aircraft, bool cockpit, bool situation, bool aircraftParts); + //! Find out whether we can connect to FSUIPC or not + static bool canConnect(); + //! Error messages static const QStringList &errorMessages() {