From 1785d63a61d062247518686334a06e6c0ca62f6b Mon Sep 17 00:00:00 2001 From: Alexander Vos Date: Sun, 20 May 2012 17:28:46 +0200 Subject: [PATCH] MP player handling and "dedicated server" --- main.cpp | 49 +++++++++++++++++++++++++++++++++++++++---- multiplayerclient.cpp | 32 ++++++++++++++++++++++++++-- multiplayerclient.h | 6 ++++++ multiplayerpacket.cpp | 6 +++++- multiplayerpacket.h | 6 +++++- multiplayerserver.cpp | 44 +++++++++++++++++++++++++++++++------- multiplayerserver.h | 8 ++++++- 7 files changed, 134 insertions(+), 17 deletions(-) diff --git a/main.cpp b/main.cpp index df6e03c..5349693 100644 --- a/main.cpp +++ b/main.cpp @@ -2,10 +2,26 @@ #include #include "mainwindow.h" - #include "randomutil.h" #include "canvas.h" #include "playerintelligence.h" +#include "multiplayerserver.h" + +const quint16 DEFAULT_PORT = 54321; + +quint16 readUShort(const QStringList &arguments, const QString &name, quint16 defaultValue = 0) +{ + if (arguments.isEmpty()) + return defaultValue; + + int index = arguments.indexOf(name); + if (index < 0 || index + 1 >= arguments.count()) + return defaultValue; + + bool ok; + quint16 value = arguments.at(index + 1).toUShort(&ok); + return ok ? value : defaultValue; +} int main(int argc, char *argv[]) { @@ -20,12 +36,37 @@ int main(int argc, char *argv[]) qRegisterMetaType("PlayerIntelligence*"); RandomUtil::init(); + QStringList arguments = a.arguments(); + +#ifdef DEBUG + qDebug() << "PlanetAttack started with arguments:" << arguments; +#endif QWidget *w; - if (a.arguments().contains("-noui")) { - w = new Canvas; + if (arguments.contains("-server")) { + QHostAddress adress = QHostAddress::Any; + quint16 port = readUShort(arguments, "-port", DEFAULT_PORT); + + w = new QWidget; // TODO: replace with dedicated server class + w->setWindowTitle("Dedicated Server (placeholder)"); + + Game *game = new Game(w); + MultiplayerServer *server = new MultiplayerServer(game, game); + if (server->listen(adress, port)) { + qDebug("The server is listening on interface %s, port %i", + qPrintable(server->serverAddress().toString()), server->serverPort()); +// game->startGameLoop(); + } else { + qCritical("Failed to start the server on interface %s, port %i: %s (error code %i)", + qPrintable(adress.toString()), port, qPrintable(server->errorString()), server->serverError()); + return 1; + } } else { - w = new MainWindow; + if (arguments.contains("-noui")) { + w = new Canvas; + } else { + w = new MainWindow; + } } w->resize(1024, 768); diff --git a/multiplayerclient.cpp b/multiplayerclient.cpp index 0bf1e54..2bc7a1c 100644 --- a/multiplayerclient.cpp +++ b/multiplayerclient.cpp @@ -7,7 +7,8 @@ MultiplayerClient::MultiplayerClient(Game *game, Player *player, QObject *parent QTcpSocket(parent), m_game(game), m_player(player), - m_packetSize(0) + m_packetSize(0), + m_playerId(-1) { connect(this, SIGNAL(connected()), SLOT(socket_connected())); connect(this, SIGNAL(disconnected()), SLOT(socket_disconnected())); @@ -60,7 +61,7 @@ void MultiplayerClient::socket_readyRead() // read and handle packet data switch ((MultiplayerPacket::PacketType)packetType) { case MultiplayerPacket::ConnectionAccepted: { - MultiplayerPacket packet(MultiplayerPacket::PlayerJoin); + MultiplayerPacket packet(MultiplayerPacket::PlayerConnect); packet.stream() << *m_player; packet.send(this); break; @@ -68,6 +69,33 @@ void MultiplayerClient::socket_readyRead() case MultiplayerPacket::ConnectionRefused: // TODO break; + case MultiplayerPacket::PlayerConnectAccepted: { + in >> m_playerId; + qDebug("playerId = %d", m_playerId); + break; + } + case MultiplayerPacket::PlayerConnectDenied: + // TODO + break; + case MultiplayerPacket::PlayerConnected: { + PlayerID playerId; + Player *player = new Player; + in >> playerId >> *player; + if (m_game->addPlayer(player)) { + m_idPlayerMap.insert(playerId, player); + qDebug("playerId = %d, name = %s", playerId, qPrintable(player->name())); + } + break; + } + case MultiplayerPacket::PlayerDisconnected: { + PlayerID playerId; + in >> playerId; + Player *player = m_idPlayerMap.value(playerId); + m_idPlayerMap.remove(playerId); + m_game->removePlayer(player); + qDebug("playerId = %d, name = %s", playerId, qPrintable(player->name())); + break; + } case MultiplayerPacket::PlanetAdded: { Planet *planet = new Planet; in >> *planet; diff --git a/multiplayerclient.h b/multiplayerclient.h index 089d126..b6309fb 100644 --- a/multiplayerclient.h +++ b/multiplayerclient.h @@ -2,11 +2,14 @@ #define MULTIPLAYERCLIENT_H #include +#include class Game; class Player; class Planet; +typedef quint8 PlayerID; + class MultiplayerClient : public QTcpSocket { Q_OBJECT @@ -27,6 +30,9 @@ private slots: Player *m_player; quint32 m_packetSize; + PlayerID m_playerId; + QHash m_idPlayerMap; + }; #endif // MULTIPLAYERCLIENT_H diff --git a/multiplayerpacket.cpp b/multiplayerpacket.cpp index 249dfd8..2c0784f 100644 --- a/multiplayerpacket.cpp +++ b/multiplayerpacket.cpp @@ -5,8 +5,12 @@ const char* MultiplayerPacket::PacketTypeNames[] = { "ConnectionAccepted", "ConnectionRefused", - "PlayerJoin", + "PlayerConnect", + "PlayerConnectAccepted", + "PlayerConnectDenied", + "PlayerConnected", "PlayerDisconnect", + "PlayerDisconnected", "PlanetAdded", "IllegalPacketType" }; diff --git a/multiplayerpacket.h b/multiplayerpacket.h index ceddca9..d590cf0 100644 --- a/multiplayerpacket.h +++ b/multiplayerpacket.h @@ -12,8 +12,12 @@ class MultiplayerPacket enum PacketType { ConnectionAccepted, // server -> client ConnectionRefused, // server -> client - PlayerJoin, // client -> server + PlayerConnect, // client -> server + PlayerConnectAccepted, // server -> client + PlayerConnectDenied, // server -> client + PlayerConnected, // server -> other clients PlayerDisconnect, // client -> server + PlayerDisconnected, // server -> other clients PlanetAdded, // client -> server -> other clients IllegalPacketType }; diff --git a/multiplayerserver.cpp b/multiplayerserver.cpp index 9cfce70..7ba01b0 100644 --- a/multiplayerserver.cpp +++ b/multiplayerserver.cpp @@ -6,7 +6,8 @@ MultiplayerServer::MultiplayerServer(Game *game, QObject *parent) : QTcpServer(parent), - m_game(game) + m_game(game), + m_nextPlayerId(1) { } @@ -56,8 +57,12 @@ void MultiplayerServer::client_disconnected() qPrintable(socket->peerAddress().toString()), socket->peerPort()); #endif - if (player != NULL) { + if (client->isConnected()) { m_game->removePlayer(player); + + MultiplayerPacket playerDisconnectedPacket(MultiplayerPacket::PlayerDisconnected); + playerDisconnectedPacket.stream() << client->id; + sendPacketToOtherClients(playerDisconnectedPacket, socket); } m_clients.remove(socket); delete client; @@ -99,11 +104,33 @@ void MultiplayerServer::client_readyRead() // read and handle packet data switch ((MultiplayerPacket::PacketType)packetType) { - case MultiplayerPacket::PlayerJoin: { + case MultiplayerPacket::PlayerConnect: { Player *player = new Player; in >> *player; if (m_game->addPlayer(player)) { client->player = player; + client->id = m_nextPlayerId++; + + // accept the player + MultiplayerPacket connectAcceptedPacket(MultiplayerPacket::PlayerConnectAccepted); + connectAcceptedPacket.stream() << client->id; + connectAcceptedPacket.send(socket); + + // send the client the other players data + foreach (Client *otherClient, m_clients.values()) { + if (otherClient != client && otherClient->isConnected()) { + MultiplayerPacket otherPlayerPacket(MultiplayerPacket::PlayerConnected); // send PlayerList in one packet? + otherPlayerPacket.stream() << otherClient->id << *otherClient->player; + otherPlayerPacket.send(socket); + } + } + + // inform the other clients about the new player + MultiplayerPacket playerConnectedPacket(MultiplayerPacket::PlayerConnected); + playerConnectedPacket.stream() << client->id << *player; + sendPacketToOtherClients(playerConnectedPacket, socket); + } else { + MultiplayerPacket(MultiplayerPacket::PlayerConnectDenied).send(socket); } break; } @@ -113,11 +140,12 @@ void MultiplayerServer::client_readyRead() case MultiplayerPacket::PlanetAdded: { Planet *planet = new Planet; in >> *planet; - m_game->addPlanet(planet); - // resend packet to all other clients - MultiplayerPacket packet(MultiplayerPacket::PlanetAdded); - packet.stream() << *planet; - sendPacketToOtherClients(packet, socket); + if (m_game->addPlanet(planet)) { + // resend packet to all other clients + MultiplayerPacket packet(MultiplayerPacket::PlanetAdded); + packet.stream() << *planet; + sendPacketToOtherClients(packet, socket); + } break; } default: diff --git a/multiplayerserver.h b/multiplayerserver.h index 098b8d2..7278604 100644 --- a/multiplayerserver.h +++ b/multiplayerserver.h @@ -9,6 +9,8 @@ class Game; class Player; +typedef quint8 PlayerID; // uint8 enough? + class MultiplayerServer : public QTcpServer { Q_OBJECT @@ -26,12 +28,16 @@ private slots: Game *m_game; struct Client { - explicit inline Client(Player *p = NULL) : player(p), packetSize(0) { } + explicit inline Client(Player *p = NULL) : player(p), id(-1), packetSize(0) { } Player *player; + PlayerID id; quint32 packetSize; + inline bool isConnected() const { return player != NULL; } }; QHash m_clients; + PlayerID m_nextPlayerId; + void incomingConnection(int socketDescriptor); void sendPacketToOtherClients(MultiplayerPacket &packet, const QTcpSocket *sender);