1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Lobby refactoring and changes

This commit is contained in:
nordsoft 2022-11-10 04:20:44 +04:00
parent ab630d43f1
commit 81a0ac2398
10 changed files with 467 additions and 229 deletions

View File

@ -33,7 +33,9 @@ set(launcher_SRCS
launcherdirs.cpp
jsonutils.cpp
updatedialog_moc.cpp
lobby/lobby.cpp
lobby/lobby_moc.cpp
lobby/lobbyroomrequest_moc.cpp
)
set(launcher_HEADERS
@ -44,7 +46,9 @@ set(launcher_HEADERS
launcherdirs.h
jsonutils.h
updatedialog_moc.h
lobby/lobby.h
lobby/lobby_moc.h
lobby/lobbyroomrequest_moc.h
main.h
)
@ -55,6 +59,7 @@ set(launcher_FORMS
mainwindow_moc.ui
updatedialog_moc.ui
lobby/lobby_moc.ui
lobby/lobbyroomrequest_moc.ui
)
if(APPLE_IOS)

114
launcher/lobby/lobby.cpp Normal file
View File

@ -0,0 +1,114 @@
/*
* lobby.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "lobby.h"
#include "../lib/GameConstants.h"
SocketLobby::SocketLobby(QObject *parent) :
QObject(parent)
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()), this, SLOT(connected()));
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
}
void SocketLobby::connectServer(const QString & host, int port, const QString & usr)
{
const int connectionTimeout = 1000;
username = usr;
emit text("Connecting to " + host + ":" + QString::number(port));
socket->connectToHost(host, port);
if(!socket->waitForDisconnected(connectionTimeout) && !isConnected)
{
emit text("Error: " + socket->errorString());
}
}
void SocketLobby::disconnectServer()
{
socket->disconnectFromHost();
}
void SocketLobby::requestNewSession(const QString & session, int totalPlayers, const QString & pswd)
{
const QString sessionMessage = ProtocolStrings[CREATE].arg(session, pswd, QString::number(totalPlayers));
send(sessionMessage);
}
void SocketLobby::requestJoinSession(const QString & session, const QString & pswd)
{
const QString sessionMessage = ProtocolStrings[JOIN].arg(session, pswd);
send(sessionMessage);
}
void SocketLobby::requestLeaveSession(const QString & session)
{
const QString sessionMessage = ProtocolStrings[LEAVE].arg(session);
send(sessionMessage);
}
void SocketLobby::requestReadySession(const QString & session)
{
const QString sessionMessage = ProtocolStrings[READY].arg(session);
send(sessionMessage);
}
void SocketLobby::send(const QString & msg)
{
int sz = msg.size();
QByteArray pack((const char *)&sz, sizeof(sz));
pack.append(qPrintable(msg));
socket->write(pack);
}
void SocketLobby::connected()
{
isConnected = true;
emit text("Connected!");
QByteArray greetingBytes;
greetingBytes.append(ProtocolVersion);
greetingBytes.append(ProtocolEncoding.size());
const QString greetingConst = QString(greetingBytes)
+ ProtocolStrings[GREETING].arg(QString::fromStdString(ProtocolEncoding),
username,
QString::fromStdString(GameConstants::VCMI_VERSION));
send(greetingConst);
}
void SocketLobby::disconnected()
{
isConnected = false;
emit disconnect();
emit text("Disconnected!");
}
void SocketLobby::bytesWritten(qint64 bytes)
{
qDebug() << "We wrote: " << bytes;
}
void SocketLobby::readyRead()
{
qDebug() << "Reading...";
emit receive(socket->readAll());
}
ServerCommand::ServerCommand(ProtocolConsts cmd, const QStringList & args):
command(cmd),
arguments(args)
{
}

101
launcher/lobby/lobby.h Normal file
View File

@ -0,0 +1,101 @@
/*
* lobby.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <QTcpSocket>
#include <QAbstractSocket>
const unsigned int ProtocolVersion = 1;
#ifdef VCMI_WINDOWS
const std::string ProtocolEncoding = "utf16";
#else
const std::string ProtocolEncoding = "utf8";
#endif
class ProtocolError: public std::runtime_error
{
public:
ProtocolError(const char * w): std::runtime_error(w) {}
};
enum ProtocolConsts
{
//client consts
GREETING, USERNAME, MESSAGE, VERSION, CREATE, JOIN, LEAVE, READY,
//server consts
SESSIONS, CREATED, JOINED, KICKED, SRVERROR, CHAT, START, STATUS, HOST
};
const QMap<ProtocolConsts, QString> ProtocolStrings
{
//client consts
{GREETING, "%1<GREETINGS>%2<VER>%3"}, //protocol_version byte, encoding bytes, encoding, name, version
{USERNAME, "<USER>%1"},
{MESSAGE, "<MSG>%1"},
{CREATE, "<NEW>%1<PSWD>%2<COUNT>%3"},
{JOIN, "<JOIN>%1<PSWD>%2"},
{LEAVE, "<LEAVE>%1"}, //session
{READY, "<READY>%1"}, //session
//server consts
{CREATED, "CREATED"},
{SESSIONS, "SESSIONS"}, //amount:session_name:joined_players:total_players:is_protected
{JOINED, "JOIN"}, //session_name:username
{KICKED, "KICK"}, //session_name:username
{START, "START"}, //session_name:uuid
{HOST, "HOST"}, //host_uuid:players_count
{STATUS, "STATUS"}, //joined_players:player_name:is_ready
{SRVERROR, "ERROR"},
{CHAT, "MSG"} //username:message
};
class ServerCommand
{
public:
ServerCommand(ProtocolConsts, const QStringList & arguments);
const ProtocolConsts command;
const QStringList arguments;
};
class SocketLobby : public QObject
{
Q_OBJECT
public:
explicit SocketLobby(QObject *parent = 0);
void connectServer(const QString & host, int port, const QString & username);
void disconnectServer();
void requestNewSession(const QString & session, int totalPlayers, const QString & pswd);
void requestJoinSession(const QString & session, const QString & pswd);
void requestLeaveSession(const QString & session);
void requestReadySession(const QString & session);
void send(const QString &);
signals:
void text(QString);
void receive(QString);
void disconnect();
public slots:
void connected();
void disconnected();
void bytesWritten(qint64 bytes);
void readyRead();
private:
QTcpSocket *socket;
bool isConnected = false;
QString username;
};

View File

@ -1,113 +1,9 @@
#include "StdInc.h"
#include "lobby_moc.h"
#include "ui_lobby_moc.h"
#include "lobbyroomrequest_moc.h"
#include "../mainwindow_moc.h"
#include "../lib/GameConstants.h"
#include "../jsonutils.h"
#include "../../lib/CConfigHandler.h"
//#include "../../lib/VCMIDirs.h"
SocketLobby::SocketLobby(QObject *parent) :
QObject(parent)
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()), this, SLOT(connected()));
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
}
void SocketLobby::connectServer(const QString & host, int port, const QString & usr)
{
const int connectionTimeout = 1000;
username = usr;
emit text("Connecting to " + host + ":" + QString::number(port));
socket->connectToHost(host, port);
if(!socket->waitForDisconnected(connectionTimeout) && !isConnected)
{
emit text("Error: " + socket->errorString());
}
}
void SocketLobby::disconnectServer()
{
socket->disconnectFromHost();
}
void SocketLobby::requestNewSession(const QString & session, int totalPlayers, const QString & pswd)
{
const QString sessionMessage = ProtocolStrings[CREATE].arg(session, pswd, QString::number(totalPlayers));
send(sessionMessage);
}
void SocketLobby::requestJoinSession(const QString & session, const QString & pswd)
{
const QString sessionMessage = ProtocolStrings[JOIN].arg(session, pswd);
send(sessionMessage);
}
void SocketLobby::requestLeaveSession(const QString & session)
{
const QString sessionMessage = ProtocolStrings[LEAVE].arg(session);
send(sessionMessage);
}
void SocketLobby::requestReadySession(const QString & session)
{
const QString sessionMessage = ProtocolStrings[READY].arg(session);
send(sessionMessage);
}
void SocketLobby::send(const QString & msg)
{
int sz = msg.size();
QByteArray pack((const char *)&sz, sizeof(sz));
pack.append(qPrintable(msg));
socket->write(pack);
}
void SocketLobby::connected()
{
isConnected = true;
emit text("Connected!");
QByteArray greetingBytes;
greetingBytes.append(ProtocolVersion);
greetingBytes.append(ProtocolEncoding.size());
const QString greetingConst = QString(greetingBytes)
+ ProtocolStrings[GREETING].arg(QString::fromStdString(ProtocolEncoding),
username,
QString::fromStdString(GameConstants::VCMI_VERSION));
send(greetingConst);
}
void SocketLobby::disconnected()
{
isConnected = false;
emit disconnect();
emit text("Disconnected!");
}
void SocketLobby::bytesWritten(qint64 bytes)
{
qDebug() << "We wrote: " << bytes;
}
void SocketLobby::readyRead()
{
qDebug() << "Reading...";
emit receive(socket->readAll());
}
ServerCommand::ServerCommand(ProtocolConsts cmd, const QStringList & args):
command(cmd),
arguments(args)
{
}
Lobby::Lobby(QWidget *parent) :
QWidget(parent),
@ -313,17 +209,14 @@ void Lobby::on_connectButton_toggled(bool checked)
void Lobby::on_newButton_clicked()
{
bool ok;
QString sessionName = QInputDialog::getText(this, tr("New session"), tr("Session name:"), QLineEdit::Normal, "", &ok);
if(ok && !sessionName.isEmpty())
socketLobby.requestNewSession(sessionName, 2, ui->passwordInput->text());
new LobbyRoomRequest(socketLobby, "", this);
}
void Lobby::on_joinButton_clicked()
{
auto * item = ui->sessionsTable->item(ui->sessionsTable->currentRow(), 0);
if(item)
socketLobby.requestJoinSession(item->text(), ui->passwordInput->text());
new LobbyRoomRequest(socketLobby, item->text(), this);
}

View File

@ -1,97 +1,6 @@
#ifndef LOBBY_MOC_H
#define LOBBY_MOC_H
#pragma once
#include <QWidget>
#include <QTcpSocket>
#include <QAbstractSocket>
const unsigned int ProtocolVersion = 1;
#ifdef VCMI_WINDOWS
const std::string ProtocolEncoding = "utf16";
#else
const std::string ProtocolEncoding = "utf8";
#endif
class ProtocolError: public std::runtime_error
{
public:
ProtocolError(const char * w): std::runtime_error(w) {}
};
enum ProtocolConsts
{
//client consts
GREETING, USERNAME, MESSAGE, VERSION, CREATE, JOIN, LEAVE, READY,
//server consts
SESSIONS, CREATED, JOINED, KICKED, SRVERROR, CHAT, START, STATUS, HOST
};
const QMap<ProtocolConsts, QString> ProtocolStrings
{
//client consts
{GREETING, "%1<GREETINGS>%2<VER>%3"}, //protocol_version byte, encoding bytes, encoding, name, version
{USERNAME, "<USER>%1"},
{MESSAGE, "<MSG>%1"},
{CREATE, "<NEW>%1<PSWD>%2<COUNT>%3"},
{JOIN, "<JOIN>%1<PSWD>%2"},
{LEAVE, "<LEAVE>%1"}, //session
{READY, "<READY>%1"}, //session
//server consts
{CREATED, "CREATED"},
{SESSIONS, "SESSIONS"}, //amount:session_name:joined_players:total_players:is_protected
{JOINED, "JOIN"}, //session_name:username
{KICKED, "KICK"}, //session_name:username
{START, "START"}, //session_name:uuid
{HOST, "HOST"}, //host_uuid:players_count
{STATUS, "STATUS"}, //joined_players:player_name:is_ready
{SRVERROR, "ERROR"},
{CHAT, "MSG"} //username:message
};
class ServerCommand
{
public:
ServerCommand(ProtocolConsts, const QStringList & arguments);
const ProtocolConsts command;
const QStringList arguments;
};
class SocketLobby : public QObject
{
Q_OBJECT
public:
explicit SocketLobby(QObject *parent = 0);
void connectServer(const QString & host, int port, const QString & username);
void disconnectServer();
void requestNewSession(const QString & session, int totalPlayers, const QString & pswd);
void requestJoinSession(const QString & session, const QString & pswd);
void requestLeaveSession(const QString & session);
void requestReadySession(const QString & session);
void send(const QString &);
signals:
void text(QString);
void receive(QString);
void disconnect();
public slots:
void connected();
void disconnected();
void bytesWritten(qint64 bytes);
void readyRead();
private:
QTcpSocket *socket;
bool isConnected = false;
QString username;
};
#include "lobby.h"
namespace Ui {
class Lobby;
@ -135,5 +44,3 @@ private:
private:
void protocolAssert(bool);
};
#endif // LOBBY_MOC_H

View File

@ -84,30 +84,6 @@
</property>
<widget class="QWidget" name="sessionsPage">
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QPushButton" name="newButton">
<property name="text">
<string>New game</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="passwordInput"/>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="joinButton">
<property name="text">
<string>Join game</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Password</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QTableWidget" name="sessionsTable">
<property name="editTriggers">
@ -136,6 +112,20 @@
</column>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="newButton">
<property name="text">
<string>New game</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="joinButton">
<property name="text">
<string>Join game</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="roomPage">

View File

@ -0,0 +1,40 @@
#include "lobbyroomrequest_moc.h"
#include "ui_lobbyroomrequest_moc.h"
LobbyRoomRequest::LobbyRoomRequest(SocketLobby & socket, const QString & room, QWidget *parent) :
QDialog(parent),
ui(new Ui::LobbyRoomRequest),
socketLobby(socket)
{
ui->setupUi(this);
ui->nameEdit->setText(room);
if(!room.isEmpty())
{
ui->nameEdit->setReadOnly(true);
ui->totalPlayers->setEnabled(false);
}
show();
}
LobbyRoomRequest::~LobbyRoomRequest()
{
delete ui;
}
void LobbyRoomRequest::on_buttonBox_accepted()
{
if(ui->nameEdit->isReadOnly())
{
socketLobby.requestJoinSession(ui->nameEdit->text(), ui->passwordEdit->text());
}
else
{
if(!ui->nameEdit->text().isEmpty())
{
int totalPlayers = ui->totalPlayers->currentIndex() + 2; //where 2 is a minimum amount of players
socketLobby.requestNewSession(ui->nameEdit->text(), totalPlayers, ui->passwordEdit->text());
}
}
}

View File

@ -0,0 +1,27 @@
#ifndef LOBBYROOMREQUEST_MOC_H
#define LOBBYROOMREQUEST_MOC_H
#include <QDialog>
#include "lobby.h"
namespace Ui {
class LobbyRoomRequest;
}
class LobbyRoomRequest : public QDialog
{
Q_OBJECT
public:
explicit LobbyRoomRequest(SocketLobby & socket, const QString & room, QWidget *parent = nullptr);
~LobbyRoomRequest();
private slots:
void on_buttonBox_accepted();
private:
Ui::LobbyRoomRequest *ui;
SocketLobby & socketLobby;
};
#endif // LOBBYROOMREQUEST_MOC_H

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LobbyRoomRequest</class>
<widget class="QDialog" name="LobbyRoomRequest">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>193</width>
<height>188</height>
</rect>
</property>
<property name="windowTitle">
<string>Room settings</string>
</property>
<property name="locale">
<locale language="English" country="UnitedStates"/>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Room name</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLineEdit" name="nameEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Maximum players</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="totalPlayers">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>3</string>
</property>
</item>
<item>
<property name="text">
<string>4</string>
</property>
</item>
<item>
<property name="text">
<string>5</string>
</property>
</item>
<item>
<property name="text">
<string>6</string>
</property>
</item>
<item>
<property name="text">
<string>7</string>
</property>
</item>
<item>
<property name="text">
<string>8</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Password (optional)</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLineEdit" name="passwordEdit"/>
</item>
<item row="5" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>LobbyRoomRequest</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>LobbyRoomRequest</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -483,6 +483,12 @@ def dispatch(cs: socket, sender: Sender, arr: bytes):
message = f":>>ERROR:Cannot create session with name {tag_value}, session with this name already exists"
send(cs, message)
return
if tag_value == "" or tag_value.startswith(" ") or len(tag_value) < 3:
#refuse creating game
message = f":>>ERROR:Cannot create session with invalid name {tag_value}"
send(cs, message)
return
rooms[tag_value] = Room(cs, tag_value)
sender.client.joined = True
@ -502,6 +508,13 @@ def dispatch(cs: socket, sender: Sender, arr: bytes):
send(cs, message)
return
if int(tag_value) < 2 or int(tag_value) > 8:
#refuse and cleanup room
deleteRoom(sender.client.room)
message = f":>>ERROR:Cannot create room with invalid amount of players"
send(cs, message)
return
sender.client.room.total = int(tag_value)
message = f":>>CREATED:{sender.client.room.name}"
send(cs, message)