refs #334 FS9 DirectPlay peer classes using CContinuousWorker.

This commit is contained in:
Mathew Sutcliffe
2014-11-16 01:09:01 +00:00
committed by Roland Winklmeier
parent 2a1541786a
commit 195c909ca0
8 changed files with 93 additions and 154 deletions

View File

@@ -21,8 +21,8 @@ namespace BlackSimPlugin
{
namespace Fs9
{
CDirectPlayPeer::CDirectPlayPeer(const QString &callsign, QObject *parent)
: QObject(parent),
CDirectPlayPeer::CDirectPlayPeer(QObject *owner, const QString &callsign)
: CContinuousWorker(owner, "peer_" + callsign),
m_callsign(callsign),
m_mutexHostList(QMutex::Recursive),
m_callbackWrapper(this, &CDirectPlayPeer::directPlayMessageHandler)

View File

@@ -13,6 +13,7 @@
#include "fs9.h"
#include "host_node.h"
#include "callback_wrapper.h"
#include "blackmisc/worker.h"
#include <QObject>
#include <QList>
#include <QMutex>
@@ -26,14 +27,13 @@ namespace BlackSimPlugin
namespace Fs9
{
//! DirectPlay peer implementation
class CDirectPlayPeer : public QObject
class CDirectPlayPeer : public BlackMisc::CContinuousWorker
{
Q_OBJECT
public:
//! Constructor
CDirectPlayPeer(const QString &callsign, QObject *parent = nullptr);
CDirectPlayPeer(QObject *owner, const QString &callsign);
//! Destructor
virtual ~CDirectPlayPeer();
@@ -45,20 +45,14 @@ namespace BlackSimPlugin
void setPlayerUserId(DPNID id) { m_playerUser = id; }
public slots:
//! Initialize DirectPlay host
virtual void init() = 0;
//! Send a custom DirectPlay message
HRESULT sendMessage(const QByteArray &data);
signals:
//! Received custom FS9 packet
void customPacketReceived(const QByteArray &data);
protected:
//! DirectPlay message handler
HRESULT directPlayMessageHandler(DWORD messageId, void *msgBuffer);

View File

@@ -17,6 +17,7 @@
#include "blackmisc/coordinategeodetic.h"
#include <QScopedArrayPointer>
using namespace BlackMisc;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::PhysicalQuantities;
@@ -24,8 +25,8 @@ namespace BlackSimPlugin
{
namespace Fs9
{
CFs9Client::CFs9Client(const QString &callsign, const CTime &updateInterval, QObject *parent) :
CDirectPlayPeer(callsign, parent),
CFs9Client::CFs9Client(QObject *owner, const QString &callsign, const CTime &updateInterval) :
CDirectPlayPeer(owner, callsign),
m_updateInterval(updateInterval)
{
}
@@ -36,14 +37,6 @@ namespace BlackSimPlugin
m_hostAddress = nullptr;
}
void CFs9Client::init()
{
initDirectPlay();
createDeviceAddress();
//enumDirectPlayHosts();
connectToSession(m_callsign);
}
void CFs9Client::sendTextMessage(const QString &textMessage)
{
MPChatText mpChatText;
@@ -55,11 +48,6 @@ namespace BlackSimPlugin
sendMessage(message);
}
void CFs9Client::disconnectFrom()
{
closeConnection();
}
void CFs9Client::setHostAddress(const QString &hostAddress)
{
HRESULT hr = S_OK;
@@ -120,6 +108,19 @@ namespace BlackSimPlugin
}
}
void CFs9Client::initialize()
{
initDirectPlay();
createDeviceAddress();
//enumDirectPlayHosts();
connectToSession(m_callsign);
}
void CFs9Client::cleanup()
{
closeConnection();
}
HRESULT CFs9Client::enumDirectPlayHosts()
{
HRESULT hr = S_OK;
@@ -251,6 +252,7 @@ namespace BlackSimPlugin
MultiPlayerPacketParser::writeType(message, CFs9Sdk::MULTIPLAYER_PACKET_ID_CHANGE_PLAYER_PLANE);
MultiPlayerPacketParser::writeSize(message, mpChangePlayerPlane.size());
message = MultiPlayerPacketParser::writeMessage(message, mpChangePlayerPlane);
CLogMessage(this).debug() << m_callsign << " connected to session.";
sendMessage(message);
m_timerId = startTimer(m_updateInterval.value(CTimeUnit::ms()));

View File

@@ -30,7 +30,6 @@ namespace BlackSimPlugin
Q_OBJECT
public:
//! Connection status
enum ClientStatus
{
@@ -38,10 +37,8 @@ namespace BlackSimPlugin
Disconnected
};
//! Constructor
CFs9Client(const QString &callsign, const BlackMisc::PhysicalQuantities::CTime &updateInterval,
QObject *parent = nullptr);
CFs9Client(QObject *owner, const QString &callsign, const BlackMisc::PhysicalQuantities::CTime &updateInterval);
//! Destructor
virtual ~CFs9Client();
@@ -53,28 +50,25 @@ namespace BlackSimPlugin
void addAircraftSituation(const BlackMisc::Aviation::CAircraftSituation &situation);
public slots:
//! \copydoc CDirectPlayPeer::init
virtual void init() override;
//! Send new text message
void sendTextMessage(const QString &textMessage);
//! Disconnect client from session
void disconnectFrom();
signals:
//! Client status changed
void statusChanged(const QString &callsign, BlackSimPlugin::Fs9::CFs9Client::ClientStatus);
protected slots:
//! Timer event slot
virtual void timerEvent(QTimerEvent *event) override;
private:
protected:
//! \copydoc CContinuousWorker::initialize
virtual void initialize() override;
//! \copydoc CContinuousWorker::cleanup
virtual void cleanup() override;
private:
/*!
* Enumerate all FS9 session hosts
* \todo Ideally host enumeration is required only once (if ever).

View File

@@ -23,8 +23,8 @@ namespace BlackSimPlugin
{
namespace Fs9
{
CFs9Host::CFs9Host(QObject *parent) :
CDirectPlayPeer(CProject::systemNameAndVersion(), parent)
CFs9Host::CFs9Host(QObject *owner) :
CDirectPlayPeer(owner, CProject::systemNameAndVersion())
{
}
@@ -63,39 +63,6 @@ namespace BlackSimPlugin
return address;
}
void CFs9Host::init()
{
initDirectPlay();
createHostAddress();
startHosting(CProject::systemNameAndVersion(), m_callsign);
}
HRESULT CFs9Host::stopHosting()
{
HRESULT hr = S_OK;
if (m_hostStatus == Terminated) return hr;
qDebug() << "Terminating host";
if (FAILED(hr = m_directPlayPeer->TerminateSession(nullptr, 0, 0)))
{
qWarning() << "Failed to terminate session!";
return hr;
}
if (FAILED(hr = m_directPlayPeer->Close(0)))
{
qWarning() << "Failed to close peer!";
return hr;
}
m_hostStatus = Terminated;
emit statusChanged(m_hostStatus);
return hr;
}
void CFs9Host::sendTextMessage(const QString &textMessage)
{
MPChatText mpChatText;
@@ -107,6 +74,19 @@ namespace BlackSimPlugin
sendMessage(message);
}
void CFs9Host::initialize()
{
initDirectPlay();
createHostAddress();
startHosting(CProject::systemNameAndVersion(), m_callsign);
}
void CFs9Host::cleanup()
{
stopHosting();
}
HRESULT CFs9Host::startHosting(const QString &session, const QString &callsign)
{
HRESULT hr = S_OK;
@@ -170,5 +150,20 @@ namespace BlackSimPlugin
emit statusChanged(m_hostStatus);
return hr;
}
HRESULT CFs9Host::stopHosting()
{
HRESULT hr = S_OK;
if (m_hostStatus == Terminated) return hr;
qDebug() << "Terminating host";
hr = m_directPlayPeer->TerminateSession(nullptr, 0, 0);
hr = m_directPlayPeer->Close(0);
m_hostStatus = Terminated;
emit statusChanged(m_hostStatus);
return hr;
}
}
}

View File

@@ -24,7 +24,6 @@ namespace BlackSimPlugin
Q_OBJECT
public:
//! Connection status
enum HostStatus
{
@@ -33,7 +32,10 @@ namespace BlackSimPlugin
};
//! Constructor
CFs9Host(QObject *parent = nullptr);
CFs9Host(QObject *owner);
//! Destructor
virtual ~CFs9Host() {}
//! Returns true if the users simulator is connected
bool isConnected() const { return m_playerUser != 0; }
@@ -42,28 +44,28 @@ namespace BlackSimPlugin
QString getHostAddress();
public slots:
//! \copydoc CDirectPlayPeer::init
virtual void init() override;
//! Terminate a current active hosting session
HRESULT stopHosting();
//! Send new text message
void sendTextMessage(const QString &textMessage);
signals:
//! Hosting status changed
void statusChanged(BlackSimPlugin::Fs9::CFs9Host::HostStatus);
private:
protected:
//! \copydoc CContinuousWorker::initialize
virtual void initialize() override;
//! \copydoc CContinuousWorker::cleanup
virtual void cleanup() override;
private:
//! Start host session
HRESULT startHosting(const QString &session, const QString &callsign);
HostStatus m_hostStatus = Terminated;
//! Terminate a current active hosting session
HRESULT stopHosting();
HostStatus m_hostStatus = Terminated;
};
}
}

View File

@@ -19,6 +19,7 @@
#include <QTimer>
#include <algorithm>
using namespace BlackMisc;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Geo;
@@ -42,30 +43,19 @@ namespace BlackSimPlugin
CSimulatorFs9::CSimulatorFs9(QObject *parent) :
ISimulator(parent),
m_fs9Host(new CFs9Host),
m_hostThread(this),
m_fs9Host(new CFs9Host(this)),
m_lobbyClient(new CLobbyClient(this)),
m_simulatorInfo(CSimulatorInfo::FS9()),
m_fsuipc(new FsCommon::CFsuipc())
{
// We move the host thread already in the constructor
m_fs9Host->moveToThread(&m_hostThread);
connect(&m_hostThread, &QThread::started, m_fs9Host, &CFs9Host::init);
connect(m_fs9Host, &CFs9Host::customPacketReceived, this, &CSimulatorFs9::ps_processFs9Message);
connect(m_fs9Host, &CFs9Host::statusChanged, this, &CSimulatorFs9::ps_changeHostStatus);
connect(&m_hostThread, &QThread::finished, m_fs9Host, &CFs9Host::deleteLater);
connect(&m_hostThread, &QThread::finished, &m_hostThread, &QThread::deleteLater);
m_hostThread.start();
connect(m_fs9Host.data(), &CFs9Host::customPacketReceived, this, &CSimulatorFs9::ps_processFs9Message);
connect(m_fs9Host.data(), &CFs9Host::statusChanged, this, &CSimulatorFs9::ps_changeHostStatus);
m_fs9Host->start();
}
CSimulatorFs9::~CSimulatorFs9()
{
disconnectFrom();
m_hostThread.quit();
m_hostThread.wait(1000);
QList<QThread *> clientThreads = m_fs9ClientThreads.values();
for (QThread *clientThread : clientThreads) clientThread->wait();
Q_ASSERT(!m_isHosting);
}
bool CSimulatorFs9::isConnected() const
@@ -95,29 +85,23 @@ namespace BlackSimPlugin
{
disconnectAllClients();
// We tell the host to terminate and stop the thread afterwards
QMetaObject::invokeMethod(m_fs9Host, "stopHosting");
emit connectionStatusChanged(ISimulator::Disconnected);
if (m_fs9Host) { m_fs9Host->quit(); }
m_fsuipc->disconnect();
return false;
m_isHosting = false;
return true;
}
void CSimulatorFs9::addRemoteAircraft(const CCallsign &callsign, const BlackMisc::Aviation::CAircraftSituation &initialSituation)
{
// Create a new client thread, set update frequency to 25 ms and start it
QThread *clientThread = new QThread(this);
CFs9Client *client = new CFs9Client(callsign.toQString(), CTime(25, CTimeUnit::ms()));
CFs9Client *client = new CFs9Client(this, callsign.toQString(), CTime(25, CTimeUnit::ms()));
client->setHostAddress(m_fs9Host->getHostAddress());
client->setPlayerUserId(m_fs9Host->getPlayerUserId());
client->moveToThread(clientThread);
connect(clientThread, &QThread::started, client, &CFs9Client::init);
connect(client, &CFs9Client::statusChanged, this, &CSimulatorFs9::ps_changeClientStatus);
m_fs9ClientThreads.insert(client, clientThread);
client->start();
m_hashFs9Clients.insert(callsign, client);
clientThread->start();
addAircraftSituation(callsign, initialSituation);
}
@@ -137,10 +121,11 @@ namespace BlackSimPlugin
{
if(!m_hashFs9Clients.contains(callsign)) return;
CFs9Client *fs9Client = m_hashFs9Clients.value(callsign);
auto fs9Client = m_hashFs9Clients.value(callsign);
// Send an async disconnect signal. When finished we will clean up
QMetaObject::invokeMethod(fs9Client, "disconnectFrom");
fs9Client->quit();
m_hashFs9Clients.remove(callsign);
}
bool CSimulatorFs9::updateOwnSimulatorCockpit(const CAircraft &ownAircraft)
@@ -294,10 +279,6 @@ namespace BlackSimPlugin
}
case CFs9Host::Terminated:
{
m_fs9Host->deleteLater();
qDebug() << "Quitting thread";
connect(&m_hostThread, &QThread::finished, &m_hostThread, &QThread::deleteLater);
m_hostThread.quit();
m_isHosting = false;
emit connectionStatusChanged(Disconnected);
break;
@@ -307,30 +288,6 @@ namespace BlackSimPlugin
}
}
void CSimulatorFs9::ps_changeClientStatus(const QString &callsign, CFs9Client::ClientStatus status)
{
switch (status)
{
case CFs9Client::Disconnected:
{
CFs9Client *client = m_hashFs9Clients.value(callsign);
Q_ASSERT(m_fs9ClientThreads.contains(client));
QThread *clientThread = m_fs9ClientThreads.value(client);
// Cleanup
client->deleteLater();
connect(clientThread, &QThread::finished, clientThread, &QThread::deleteLater);
clientThread->quit();
m_fs9ClientThreads.remove(client);
m_hashFs9Clients.remove(callsign);
break;
}
default:
break;
}
}
void CSimulatorFs9::updateOwnAircraftFromSim(const CAircraft &ownAircraft)
{
m_ownAircraft.setCom1System(ownAircraft.getCom1System());
@@ -340,7 +297,7 @@ namespace BlackSimPlugin
void CSimulatorFs9::disconnectAllClients()
{
// Stop all FS9 client threads
// Stop all FS9 client tasks
for (auto fs9Client : m_hashFs9Clients.keys())
{
removeRemoteAircraft(fs9Client);

View File

@@ -142,9 +142,6 @@ namespace BlackSimPlugin
//! Change DirectPlay host status
void ps_changeHostStatus(BlackSimPlugin::Fs9::CFs9Host::HostStatus status);
//! Change client status for callsign
void ps_changeClientStatus(const QString &callsign, BlackSimPlugin::Fs9::CFs9Client::ClientStatus status);
private:
//! Called when data about our own aircraft are received
@@ -153,16 +150,14 @@ namespace BlackSimPlugin
void disconnectAllClients();
// DirectPlay object handling
CFs9Host *m_fs9Host = nullptr;
QThread m_hostThread;
QPointer<CFs9Host> m_fs9Host;
bool m_isHosting = false; //!< Is sim connected
bool m_startedLobbyConnection = false;
bool m_syncTime = false; //!< Time synchronized?
int m_syncDeferredCounter = 0; //!< Set when synchronized, used to wait some time
bool m_simPaused = false; //!< Simulator paused?
QHash<BlackMisc::Aviation::CCallsign, CFs9Client *> m_hashFs9Clients;
QHash<CFs9Client *, QThread *> m_fs9ClientThreads;
QHash<BlackMisc::Aviation::CCallsign, QPointer<CFs9Client>> m_hashFs9Clients;
CLobbyClient *m_lobbyClient;