1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

Support mod list

This commit is contained in:
nordsoft 2022-11-17 03:15:26 +04:00
parent 4527bd1a61
commit 05e4188908
9 changed files with 158 additions and 35 deletions

View File

@ -39,15 +39,15 @@ void SocketLobby::disconnectServer()
socket->disconnectFromHost();
}
void SocketLobby::requestNewSession(const QString & session, int totalPlayers, const QString & pswd)
void SocketLobby::requestNewSession(const QString & session, int totalPlayers, const QString & pswd, const QMap<QString, QString> & mods)
{
const QString sessionMessage = ProtocolStrings[CREATE].arg(session, pswd, QString::number(totalPlayers));
const QString sessionMessage = ProtocolStrings[CREATE].arg(session, pswd, QString::number(totalPlayers), prepareModsClientString(mods));
send(sessionMessage);
}
void SocketLobby::requestJoinSession(const QString & session, const QString & pswd)
void SocketLobby::requestJoinSession(const QString & session, const QString & pswd, const QMap<QString, QString> & mods)
{
const QString sessionMessage = ProtocolStrings[JOIN].arg(session, pswd);
const QString sessionMessage = ProtocolStrings[JOIN].arg(session, pswd, prepareModsClientString(mods));
send(sessionMessage);
}
@ -111,3 +111,13 @@ ServerCommand::ServerCommand(ProtocolConsts cmd, const QStringList & args):
arguments(args)
{
}
QString prepareModsClientString(const QMap<QString, QString> & mods)
{
QStringList result;
for(auto & mod : mods.keys())
{
result << mod + "&" + mods[mod];
}
return result.join(";");
}

View File

@ -12,7 +12,7 @@
#include <QTcpSocket>
#include <QAbstractSocket>
const unsigned int ProtocolVersion = 1;
const unsigned int ProtocolVersion = 2;
const std::string ProtocolEncoding = "utf8";
class ProtocolError: public std::runtime_error
@ -27,7 +27,7 @@ enum ProtocolConsts
GREETING, USERNAME, MESSAGE, VERSION, CREATE, JOIN, LEAVE, READY,
//server consts
SESSIONS, CREATED, JOINED, KICKED, SRVERROR, CHAT, START, STATUS, HOST
SESSIONS, CREATED, JOINED, KICKED, SRVERROR, CHAT, START, STATUS, HOST, MODS
};
const QMap<ProtocolConsts, QString> ProtocolStrings
@ -36,8 +36,8 @@ const QMap<ProtocolConsts, QString> ProtocolStrings
{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"},
{CREATE, "<NEW>%1<PSWD>%2<COUNT>%3<MODS>%4"}, //last placeholder for the mods
{JOIN, "<JOIN>%1<PSWD>%2<MODS>%3"}, //last placeholder for the mods
{LEAVE, "<LEAVE>%1"}, //session
{READY, "<READY>%1"}, //session
@ -50,6 +50,7 @@ const QMap<ProtocolConsts, QString> ProtocolStrings
{HOST, "HOST"}, //host_uuid:players_count
{STATUS, "STATUS"}, //joined_players:player_name:is_ready
{SRVERROR, "ERROR"},
{MODS, "MODS"}, //amount:modname:modversion
{CHAT, "MSG"} //username:message
};
@ -69,8 +70,8 @@ public:
explicit SocketLobby(QObject *parent = 0);
void connectServer(const QString & host, int port, const QString & username, int timeout);
void disconnectServer();
void requestNewSession(const QString & session, int totalPlayers, const QString & pswd);
void requestJoinSession(const QString & session, const QString & pswd);
void requestNewSession(const QString & session, int totalPlayers, const QString & pswd, const QMap<QString, QString> & mods);
void requestJoinSession(const QString & session, const QString & pswd, const QMap<QString, QString> & mods);
void requestLeaveSession(const QString & session);
void requestReadySession(const QString & session);
@ -93,5 +94,6 @@ private:
QTcpSocket *socket;
bool isConnected = false;
QString username;
};
QString prepareModsClientString(const QMap<QString, QString> & mods);

View File

@ -4,6 +4,7 @@
#include "ui_lobby_moc.h"
#include "lobbyroomrequest_moc.h"
#include "../mainwindow_moc.h"
#include "../modManager/cmodlist.h"
#include "../../lib/CConfigHandler.h"
Lobby::Lobby(QWidget *parent) :
@ -27,11 +28,35 @@ Lobby::~Lobby()
delete ui;
}
QMap<QString, QString> Lobby::buildModsMap() const
{
QMap<QString, QString> result;
const auto & modlist = qobject_cast<MainWindow*>(qApp->activeWindow())->getModList();
for(auto & modname : modlist.getModList())
{
auto mod = modlist.getMod(modname);
if(mod.isEnabled())
{
result[modname] = mod.getValue("version").toString();
}
}
return result;
}
bool Lobby::isModAvailable(const QString & modName, const QString & modVersion) const
{
const auto & modlist = qobject_cast<MainWindow*>(qApp->activeWindow())->getModList();
if(!modlist.hasMod(modName))
return false;
auto mod = modlist.getMod(modName);
return (mod.isInstalled () || mod.isAvailable()) && (mod.getValue("version") == modVersion);
}
void Lobby::serverCommand(const ServerCommand & command) try
{
//initialize variables outside of switch block
const QString statusPlaceholder("%1 %2\n");
QString resText;
const auto & args = command.arguments;
int amount, tagPoint;
QString joinStr;
@ -40,8 +65,8 @@ void Lobby::serverCommand(const ServerCommand & command) try
case SRVERROR:
protocolAssert(args.size());
chatMessage("System error", args[0], true);
if(authentificationStatus == 0)
authentificationStatus = 2;
if(authentificationStatus == AuthStatus::NONE)
authentificationStatus = AuthStatus::ERROR;
break;
case CREATED:
@ -98,19 +123,49 @@ void Lobby::serverCommand(const ServerCommand & command) try
}
break;
case MODS: {
protocolAssert(args.size() > 0);
amount = args[0].toInt();
protocolAssert(amount * 2 == (args.size() - 1));
tagPoint = 1;
ui->modsList->clear();
auto enabledMods = buildModsMap();
for(int i = 0; i < amount; ++i, tagPoint += 2)
{
if(enabledMods.contains(args[tagPoint]))
{
if(enabledMods[args[tagPoint]] == args[tagPoint + 1])
enabledMods.remove(args[tagPoint]);
else
ui->modsList->addItem(new QListWidgetItem(QIcon("icons:mod-update.png"), QString("%1 (v%2)").arg(args[tagPoint], args[tagPoint + 1])));
}
else if(isModAvailable(args[tagPoint], args[tagPoint + 1]))
ui->modsList->addItem(new QListWidgetItem(QIcon("icons:mod-enabled.png"), QString("%1 (v%2)").arg(args[tagPoint], args[tagPoint + 1])));
else
ui->modsList->addItem(new QListWidgetItem(QIcon("icons:mod-delete.png"), QString("%1 (v%2)").arg(args[tagPoint], args[tagPoint + 1])));
}
for(auto & remainMod : enabledMods.keys())
{
ui->modsList->addItem(new QListWidgetItem(QIcon("icons:mod-disabled.png"), QString("%1 (v%2)").arg(remainMod, enabledMods[remainMod])));
}
if(!ui->modsList->count())
ui->modsList->addItem("No issues detected");
break;
}
case STATUS:
protocolAssert(args.size() > 0);
amount = args[0].toInt();
protocolAssert(amount * 2 == (args.size() - 1));
tagPoint = 1;
ui->roomChat->clear();
resText.clear();
ui->playersList->clear();
for(int i = 0; i < amount; ++i, tagPoint += 2)
{
resText += statusPlaceholder.arg(args[tagPoint], args[tagPoint + 1] == "True" ? "ready" : "");
ui->playersList->addItem(args[tagPoint]);
}
ui->roomChat->setPlainText(resText);
break;
case START: {
@ -132,19 +187,23 @@ void Lobby::serverCommand(const ServerCommand & command) try
break;
}
case CHAT:
case CHAT: {
protocolAssert(args.size() > 1);
QString msg;
for(int i = 1; i < args.size(); ++i)
msg += args[i];
chatMessage(args[0], msg);
break;
}
default:
sysMessage("Unknown server command");
}
if(authentificationStatus == 2)
if(authentificationStatus == AuthStatus::ERROR)
socketLobby.disconnectServer();
else
authentificationStatus = 1;
authentificationStatus = AuthStatus::OK;
}
catch(const ProtocolError & e)
{
@ -177,7 +236,7 @@ catch(const ProtocolError & e)
void Lobby::onDisconnected()
{
authentificationStatus = 0;
authentificationStatus = AuthStatus::NONE;
ui->stackedWidget->setCurrentWidget(ui->sessionsPage);
ui->connectButton->setChecked(false);
}
@ -217,7 +276,7 @@ void Lobby::on_connectButton_toggled(bool checked)
{
if(checked)
{
authentificationStatus = 0;
authentificationStatus = AuthStatus::NONE;
username = ui->userEdit->text();
const int connectionTimeout = settings["launcher"]["connectionTimeout"].Integer();
@ -241,7 +300,7 @@ void Lobby::on_connectButton_toggled(bool checked)
void Lobby::on_newButton_clicked()
{
new LobbyRoomRequest(socketLobby, "", this);
new LobbyRoomRequest(socketLobby, "", buildModsMap(), this);
}
void Lobby::on_joinButton_clicked()
@ -251,9 +310,9 @@ void Lobby::on_joinButton_clicked()
{
auto isPrivate = ui->sessionsTable->item(ui->sessionsTable->currentRow(), 2)->data(Qt::UserRole).toBool();
if(isPrivate)
new LobbyRoomRequest(socketLobby, item->text(), this);
new LobbyRoomRequest(socketLobby, item->text(), buildModsMap(), this);
else
socketLobby.requestJoinSession(item->text(), "");
socketLobby.requestJoinSession(item->text(), "", buildModsMap());
}
}

View File

@ -42,8 +42,17 @@ private:
QString username;
QStringList gameArgs;
int authentificationStatus = 0;
enum AuthStatus
{
NONE, OK, ERROR
};
AuthStatus authentificationStatus = NONE;
private:
QMap<QString, QString> buildModsMap() const;
bool isModAvailable(const QString & modName, const QString & modVersion) const;
void protocolAssert(bool);
};

View File

@ -148,14 +148,34 @@
</widget>
<widget class="QWidget" name="roomPage">
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<item row="4" column="0">
<widget class="QPushButton" name="buttonLeave">
<property name="text">
<string>Leave</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="3" column="0" colspan="2">
<widget class="QListWidget" name="modsList">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QListWidget" name="playersList">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="buttonReady">
<property name="text">
<string>Ready</string>
@ -163,7 +183,18 @@
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QPlainTextEdit" name="roomChat"/>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Players in the room</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Mods mismatch</string>
</property>
</widget>
</item>
</layout>
</widget>

View File

@ -1,10 +1,11 @@
#include "lobbyroomrequest_moc.h"
#include "ui_lobbyroomrequest_moc.h"
LobbyRoomRequest::LobbyRoomRequest(SocketLobby & socket, const QString & room, QWidget *parent) :
LobbyRoomRequest::LobbyRoomRequest(SocketLobby & socket, const QString & room, const QMap<QString, QString> & mods, QWidget *parent) :
QDialog(parent),
ui(new Ui::LobbyRoomRequest),
socketLobby(socket)
socketLobby(socket),
mods(mods)
{
ui->setupUi(this);
ui->nameEdit->setText(room);
@ -26,14 +27,14 @@ void LobbyRoomRequest::on_buttonBox_accepted()
{
if(ui->nameEdit->isReadOnly())
{
socketLobby.requestJoinSession(ui->nameEdit->text(), ui->passwordEdit->text());
socketLobby.requestJoinSession(ui->nameEdit->text(), ui->passwordEdit->text(), mods);
}
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());
socketLobby.requestNewSession(ui->nameEdit->text(), totalPlayers, ui->passwordEdit->text(), mods);
}
}
}

View File

@ -13,7 +13,7 @@ class LobbyRoomRequest : public QDialog
Q_OBJECT
public:
explicit LobbyRoomRequest(SocketLobby & socket, const QString & room, QWidget *parent = nullptr);
explicit LobbyRoomRequest(SocketLobby & socket, const QString & room, const QMap<QString, QString> & mods, QWidget *parent = nullptr);
~LobbyRoomRequest();
private slots:
@ -22,6 +22,7 @@ private slots:
private:
Ui::LobbyRoomRequest *ui;
SocketLobby & socketLobby;
QMap<QString, QString> mods;
};
#endif // LOBBYROOMREQUEST_MOC_H

View File

@ -116,3 +116,8 @@ void MainWindow::on_startGameButton_clicked()
{
startGame({});
}
const CModList & MainWindow::getModList() const
{
return ui->modlistView->getModList();
}

View File

@ -19,6 +19,8 @@ const QString appName = "VCMI Launcher";
}
class QTableWidgetItem;
class CModList;
class MainWindow : public QMainWindow
{
@ -31,6 +33,9 @@ private:
public:
explicit MainWindow(QWidget * parent = 0);
~MainWindow();
const CModList & getModList() const;
public slots:
void on_startGameButton_clicked();