Connect/disconnect and join game/room intents.

Took 3 hours 14 minutes

Took 2 seconds
This commit is contained in:
Lukas Brübach 2026-04-14 07:27:00 +02:00
parent 47a80ddb12
commit 9729c6668d
26 changed files with 514 additions and 3 deletions

View file

@ -0,0 +1,14 @@
#ifndef COCKATRICE_CONTEXT_CONNECT_TO_SERVER_H
#define COCKATRICE_CONTEXT_CONNECT_TO_SERVER_H
#include <QString>
struct ContextConnectToServer
{
QString hostname;
QString port;
QString username;
QString password;
};
#endif // COCKATRICE_CONTEXT_CONNECT_TO_SERVER_H

View file

@ -0,0 +1,11 @@
#ifndef COCKATRICE_CONTEXT_JOIN_GAME_H
#define COCKATRICE_CONTEXT_JOIN_GAME_H
#include "context_join_room.h"
struct ContextJoinGame
{
ContextJoinRoom roomContext;
int gameId;
};
#endif // COCKATRICE_CONTEXT_JOIN_GAME_H

View file

@ -0,0 +1,14 @@
#ifndef COCKATRICE_CONTEXT_JOIN_ROOM_H
#define COCKATRICE_CONTEXT_JOIN_ROOM_H
#include "context_connect_to_server.h"
#include <QString>
struct ContextJoinRoom
{
ContextConnectToServer serverContext;
int roomId;
};
#endif // COCKATRICE_CONTEXT_JOIN_ROOM_H

View file

@ -0,0 +1 @@
#include "intent_connect_to_server.h"

View file

@ -0,0 +1,54 @@
#ifndef COCKATRICE_INTENT_CONNECT_TO_SERVER_H
#define COCKATRICE_INTENT_CONNECT_TO_SERVER_H
#include "contexts/context_connect_to_server.h"
#include "intent.h"
#include "intent_disconnect_from_server.h"
#include "remote_client.h"
#include <QTimer>
class IntentConnectToServer : public Intent
{
Q_OBJECT
public:
IntentConnectToServer(RemoteClient *_remoteClient, ContextConnectToServer *_context)
: Intent(), remoteClient(_remoteClient), context(_context)
{
}
protected:
bool checkPrecondition() const override
{
return remoteClient->getStatus() == ClientStatus::StatusDisconnected;
}
void onPreconditionSatisfied() override
{
remoteClient->connectToServer(context->hostname, context->port.toUInt(), context->username, context->password);
connect(remoteClient, &RemoteClient::statusChanged, this, &IntentConnectToServer::onStatusChanged);
}
void onPreconditionNotSatisfied() override
{
runDependency(new IntentDisconnectFromServer(remoteClient));
}
private:
RemoteClient *remoteClient;
ContextConnectToServer *context;
private slots:
void onStatusChanged(ClientStatus status)
{
if (status == ClientStatus::StatusLoggedIn) {
auto timer = new QTimer(this);
timer->setSingleShot(true);
timer->setInterval(2000);
connect(timer, &QTimer::timeout, this, &IntentConnectToServer::finished);
timer->start();
}
}
};
#endif // COCKATRICE_INTENT_CONNECT_TO_SERVER_H

View file

@ -0,0 +1 @@
#include "intent_disconnect_from_server.h"

View file

@ -0,0 +1,47 @@
#ifndef COCKATRICE_INTENT_DISCONNECT_FROM_SERVER_H
#define COCKATRICE_INTENT_DISCONNECT_FROM_SERVER_H
#include "intent.h"
#include "remote_client.h"
class IntentDisconnectFromServer : public Intent
{
Q_OBJECT
public:
IntentDisconnectFromServer(RemoteClient *_remoteClient) : Intent(), remoteClient(_remoteClient)
{
}
protected:
bool checkPrecondition() const override
{
return remoteClient->getStatus() == ClientStatus::StatusDisconnected;
}
void onPreconditionSatisfied() override
{
qWarning() << "Client disconnected, disconnect is finished";
emit finished();
}
void onPreconditionNotSatisfied() override
{
qWarning() << "Client not disconnected, hooking up signal and disconnecting." << remoteClient->getStatus();
connect(remoteClient, &RemoteClient::statusChanged, this, &IntentDisconnectFromServer::onStatusChanged);
remoteClient->disconnectFromServer();
}
private:
RemoteClient *remoteClient;
private slots:
void onStatusChanged(ClientStatus status)
{
qWarning() << "Client Status changed: " << status;
if (status == ClientStatus::StatusDisconnected) {
qWarning() << "Client disconnected, finished";
emit finished();
}
}
};
#endif // COCKATRICE_INTENT_DISCONNECT_FROM_SERVER_H

View file

@ -0,0 +1 @@
#include "intent_join_server_game.h"

View file

@ -0,0 +1,63 @@
#ifndef COCKATRICE_INTENT_JOIN_SERVER_GAME_H
#define COCKATRICE_INTENT_JOIN_SERVER_GAME_H
#include "../widgets/server/game_selector.h"
#include "../widgets/tabs/tab_room.h"
#include "../widgets/tabs/tab_server.h"
#include "../widgets/tabs/tab_supervisor.h"
#include "contexts/context_join_game.h"
#include "contexts/context_join_room.h"
#include "intent.h"
#include "intent_join_server_room.h"
#include "remote_client.h"
class IntentJoinServerGame : public Intent
{
Q_OBJECT
public:
IntentJoinServerGame(TabSupervisor *_tabSupervisor, RemoteClient *_remoteClient, ContextJoinGame *_context)
: Intent(), tabSupervisor(_tabSupervisor), remoteClient(_remoteClient), context(_context)
{
}
protected:
bool checkPrecondition() const override
{
if (remoteClient->getStatus() != ClientStatus::StatusLoggedIn) {
return false;
}
if (remoteClient->peerName() != context->roomContext.serverContext.hostname) {
return false;
}
if (QString::number(remoteClient->peerPort()) != context->roomContext.serverContext.port) {
return false;
}
if (!tabSupervisor->getRoomTabs()[context->roomContext.roomId]) {
qWarning() << "No room tab";
return false;
};
return true;
}
void onPreconditionSatisfied() override
{
qWarning() << "All lights green, joining game";
TabRoom *room = tabSupervisor->getRoomTabs()[context->roomContext.roomId];
room->getGameSelector()->joinGameById(context->gameId);
}
void onPreconditionNotSatisfied() override
{
runDependency(new IntentJoinServerRoom(tabSupervisor, remoteClient, &context->roomContext));
}
private:
TabSupervisor *tabSupervisor;
RemoteClient *remoteClient;
ContextJoinGame *context;
};
#endif // COCKATRICE_INTENT_JOIN_SERVER_GAME_H

View file

@ -0,0 +1 @@
#include "intent_join_server_room.h"

View file

@ -0,0 +1,58 @@
#ifndef COCKATRICE_INTENT_JOIN_SERVER_ROOM_H
#define COCKATRICE_INTENT_JOIN_SERVER_ROOM_H
#include "../widgets/tabs/tab_server.h"
#include "../widgets/tabs/tab_supervisor.h"
#include "contexts/context_connect_to_server.h"
#include "contexts/context_join_room.h"
#include "intent.h"
#include "intent_connect_to_server.h"
#include "intent_disconnect_from_server.h"
#include "remote_client.h"
class IntentJoinServerRoom : public Intent
{
Q_OBJECT
public:
IntentJoinServerRoom(TabSupervisor *_tabSupervisor, RemoteClient *_remoteClient, ContextJoinRoom *_context)
: Intent(), tabSupervisor(_tabSupervisor), remoteClient(_remoteClient), context(_context)
{
}
protected:
bool checkPrecondition() const override
{
if (remoteClient->getStatus() != ClientStatus::StatusLoggedIn) {
return false;
}
if (remoteClient->peerName() != context->serverContext.hostname) {
return false;
}
if (QString::number(remoteClient->peerPort()) != context->serverContext.port) {
return false;
}
return true;
}
void onPreconditionSatisfied() override
{
auto tabServer = tabSupervisor->getTabServer();
tabServer->joinRoom(context->roomId, true);
connect(tabServer, &TabServer::roomJoined, this, &IntentJoinServerRoom::finished);
}
void onPreconditionNotSatisfied() override
{
runDependency(new IntentConnectToServer(remoteClient, &context->serverContext));
}
private:
TabSupervisor *tabSupervisor;
RemoteClient *remoteClient;
ContextJoinRoom *context;
};
#endif // COCKATRICE_INTENT_JOIN_SERVER_ROOM_H

View file

@ -0,0 +1 @@
#include "intent_login.h"

View file

@ -0,0 +1,52 @@
#ifndef COCKATRICE_INTENT_LOGIN_H
#define COCKATRICE_INTENT_LOGIN_H
#include "../../client/settings/cache_settings.h"
#include "contexts/context_connect_to_server.h"
#include "intent.h"
#include "remote_client.h"
class IntentGetLoginCredentials : public Intent
{
Q_OBJECT
public:
IntentGetLoginCredentials(RemoteClient *_remoteClient, ContextConnectToServer *_context)
: Intent(), remoteClient(_remoteClient), context(_context)
{
}
protected:
bool checkPrecondition() const override
{
ServersSettings &servers = SettingsCache::instance().servers();
return servers.hasLoginData(context->hostname, context->port);
}
void onPreconditionSatisfied() override
{
ServersSettings &servers = SettingsCache::instance().servers();
auto index = servers.findServerIndex(context->hostname, context->port);
if (index >= 0) {
context->username =
servers.getValue(QString("username%1").arg(index), "server", "server_details").toString();
context->password =
servers.getValue(QString("password%1").arg(index), "server", "server_details").toString();
emit finished();
qWarning() << "Using saved credentials";
} else {
qWarning() << "No saved server entry";
}
}
void onPreconditionNotSatisfied() override
{
}
private:
RemoteClient *remoteClient;
ContextConnectToServer *context;
};
#endif // COCKATRICE_INTENT_LOGIN_H

View file

@ -0,0 +1,67 @@
#include "url_parser.h"
#include "../window_main.h"
#include "contexts/context_join_room.h"
#include "intent_join_server_game.h"
#include "intent_join_server_room.h"
#include "intent_login.h"
#include <QDebug>
#include <QUrl>
#include <QUrlQuery>
IntentUrlParser::IntentUrlParser(QObject *parent, MainWindow *_mainWindow) : QObject(parent), mainWindow(_mainWindow)
{
}
void IntentUrlParser::handle(const QString &urlStr)
{
QUrl url(urlStr);
if (url.scheme() != "cockatrice")
return;
const QString action = url.host();
QUrlQuery query(url);
if (action == "joingame") {
handleJoinGame(query);
} else if (action == "opendeck") {
// handleOpenDeck(query);
} else {
qWarning() << "Unknown intent:" << action;
}
}
void IntentUrlParser::handleJoinGame(const QUrlQuery &query)
{
auto ctx = new ContextJoinGame();
ctx->roomContext.serverContext.hostname = query.queryItemValue("hostname");
ctx->roomContext.serverContext.port = query.queryItemValue("port");
bool ok = false;
ctx->roomContext.roomId = query.queryItemValue("roomid").toInt(&ok);
if (!ok) {
qWarning() << "Invalid or missing roomId";
return;
}
ok = false;
ctx->gameId = query.queryItemValue("gameid").toInt(&ok);
if (!ok) {
qWarning() << "Invalid or missing gameId";
return;
}
auto getLoginCredentialsIntent =
new IntentGetLoginCredentials(mainWindow->getRemoteClient(), &ctx->roomContext.serverContext);
auto joinGameIntent = new IntentJoinServerGame(mainWindow->getTabSupervisor(), mainWindow->getRemoteClient(), ctx);
connect(getLoginCredentialsIntent, &Intent::finished, joinGameIntent, &Intent::execute);
getLoginCredentialsIntent->execute();
}

View file

@ -0,0 +1,22 @@
#ifndef COCKATRICE_URL_PARSER_H
#define COCKATRICE_URL_PARSER_H
#include <QObject>
#include <qt5/QtCore/qurlquery.h>
class MainWindow;
class IntentUrlParser : public QObject
{
Q_OBJECT
public:
IntentUrlParser(QObject *parent, MainWindow *mainWindow);
void handle(const QString &urlStr);
void handleJoinGame(const QUrlQuery &query);
void parse(QString url);
private:
MainWindow *mainWindow;
};
#endif // COCKATRICE_URL_PARSER_H

View file

@ -307,6 +307,7 @@ void GameSelector::customContextMenu(const QPoint &point)
connect(&getGameInfo, &QAction::triggered, this, [=, this]() {
const ServerInfo_Game &gameInfo = gameListModel->getGame(index.data(Qt::UserRole).toInt());
const QMap<int, QString> &gameTypes = gameListModel->getGameTypes().value(gameInfo.room_id());
qWarning() << "Game Id: " << gameInfo.game_id();
DlgCreateGame dlg(gameInfo, gameTypes, this);
dlg.exec();
@ -376,6 +377,24 @@ void GameSelector::joinGame(const bool asSpectator, const bool asJudge)
disableButtons();
}
bool GameSelector::joinGameById(int gameId)
{
auto *model = gameListView->model();
for (int row = 0; row < model->rowCount(); ++row) {
QModelIndex idx = model->index(row, 0);
const ServerInfo_Game &game = gameListModel->getGame(idx.data(Qt::UserRole).toInt());
if (game.game_id() == gameId) {
gameListView->setCurrentIndex(idx);
joinGame();
return true;
}
}
qWarning() << "Game" << gameId << "not found";
return false;
}
void GameSelector::disableButtons()
{
if (createButton) {

View file

@ -202,6 +202,7 @@ public:
* @param info The ServerInfo_Game object containing information about the game to update.
*/
void processGameInfo(const ServerInfo_Game &info);
bool joinGameById(int gameId);
};
#endif

View file

@ -125,6 +125,10 @@ public:
{
return ownUser;
}
[[nodiscard]] GameSelector *getGameSelector() const
{
return gameSelector;
}
PendingCommand *prepareRoomCommand(const ::google::protobuf::Message &cmd);
void sendRoomCommand(PendingCommand *pend);

View file

@ -51,7 +51,6 @@ signals:
void roomJoined(const ServerInfo_Room &info, bool setCurrent);
private slots:
void processServerMessageEvent(const Event_ServerMessage &event);
void joinRoom(int id, bool setCurrent);
void joinRoomFinished(const Response &resp, const CommandContainer &commandContainer, const QVariant &extraData);
private:
@ -62,6 +61,7 @@ private:
public:
TabServer(TabSupervisor *_tabSupervisor, AbstractClient *_client);
void joinRoom(int id, bool setCurrent);
void retranslateUi() override;
[[nodiscard]] QString getTabText() const override
{

View file

@ -149,6 +149,10 @@ public:
{
return userListManager;
}
[[nodiscard]] TabServer *getTabServer() const
{
return tabServer;
}
[[nodiscard]] const QMap<int, TabRoom *> &getRoomTabs() const
{
return roomTabs;

View file

@ -150,6 +150,11 @@ public:
}
~MainWindow() override;
RemoteClient *getRemoteClient() const
{
return client;
};
TabSupervisor *getTabSupervisor() const
{
return tabSupervisor;