Support starting games with fewer than max players (#5338)

This commit is contained in:
Zach H 2024-12-26 18:32:20 -05:00 committed by GitHub
parent 956c12eb32
commit 6dfd354973
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 50 additions and 16 deletions

View file

@ -106,11 +106,14 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
loadRemoteButton = new QPushButton; loadRemoteButton = new QPushButton;
readyStartButton = new ToggleButton; readyStartButton = new ToggleButton;
readyStartButton->setEnabled(false); readyStartButton->setEnabled(false);
forceStartGameButton = new QPushButton;
forceStartGameButton->setEnabled(parent->isHost());
sideboardLockButton = new ToggleButton; sideboardLockButton = new ToggleButton;
sideboardLockButton->setEnabled(false); sideboardLockButton->setEnabled(false);
connect(loadLocalButton, SIGNAL(clicked()), this, SLOT(loadLocalDeck())); connect(loadLocalButton, SIGNAL(clicked()), this, SLOT(loadLocalDeck()));
connect(readyStartButton, SIGNAL(clicked()), this, SLOT(readyStart())); connect(readyStartButton, SIGNAL(clicked()), this, SLOT(readyStart()));
connect(forceStartGameButton, &QPushButton::clicked, this, &DeckViewContainer::forceStart);
connect(sideboardLockButton, SIGNAL(clicked()), this, SLOT(sideboardLockButtonClicked())); connect(sideboardLockButton, SIGNAL(clicked()), this, SLOT(sideboardLockButtonClicked()));
connect(sideboardLockButton, SIGNAL(stateChanged()), this, SLOT(updateSideboardLockButtonText())); connect(sideboardLockButton, SIGNAL(stateChanged()), this, SLOT(updateSideboardLockButtonText()));
@ -125,6 +128,9 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
buttonHBox->addWidget(loadRemoteButton); buttonHBox->addWidget(loadRemoteButton);
buttonHBox->addWidget(readyStartButton); buttonHBox->addWidget(readyStartButton);
buttonHBox->addWidget(sideboardLockButton); buttonHBox->addWidget(sideboardLockButton);
if (forceStartGameButton->isEnabled()) {
buttonHBox->addWidget(forceStartGameButton);
}
buttonHBox->setContentsMargins(0, 0, 0, 0); buttonHBox->setContentsMargins(0, 0, 0, 0);
buttonHBox->addStretch(); buttonHBox->addStretch();
deckView = new DeckView; deckView = new DeckView;
@ -147,6 +153,7 @@ void DeckViewContainer::retranslateUi()
loadLocalButton->setText(tr("Load deck...")); loadLocalButton->setText(tr("Load deck..."));
loadRemoteButton->setText(tr("Load remote deck...")); loadRemoteButton->setText(tr("Load remote deck..."));
readyStartButton->setText(tr("Ready to start")); readyStartButton->setText(tr("Ready to start"));
forceStartGameButton->setText(tr("Force start"));
updateSideboardLockButtonText(); updateSideboardLockButtonText();
} }
@ -155,6 +162,7 @@ void DeckViewContainer::setButtonsVisible(bool _visible)
loadLocalButton->setVisible(_visible); loadLocalButton->setVisible(_visible);
loadRemoteButton->setVisible(_visible); loadRemoteButton->setVisible(_visible);
readyStartButton->setVisible(_visible); readyStartButton->setVisible(_visible);
forceStartGameButton->setVisible(_visible);
sideboardLockButton->setVisible(_visible); sideboardLockButton->setVisible(_visible);
} }
@ -338,6 +346,14 @@ void DeckViewContainer::readyStart()
parentGame->sendGameCommand(cmd, playerId); parentGame->sendGameCommand(cmd, playerId);
} }
void DeckViewContainer::forceStart()
{
Command_ReadyStart cmd;
cmd.set_force_start(true);
cmd.set_ready(true);
parentGame->sendGameCommand(cmd, playerId);
}
void DeckViewContainer::sideboardLockButtonClicked() void DeckViewContainer::sideboardLockButtonClicked()
{ {
Command_SetSideboardLock cmd; Command_SetSideboardLock cmd;

View file

@ -86,7 +86,7 @@ class DeckViewContainer : public QWidget
{ {
Q_OBJECT Q_OBJECT
private: private:
QPushButton *loadLocalButton, *loadRemoteButton; QPushButton *loadLocalButton, *loadRemoteButton, *forceStartGameButton;
ToggleButton *readyStartButton, *sideboardLockButton; ToggleButton *readyStartButton, *sideboardLockButton;
DeckView *deckView; DeckView *deckView;
TabGame *parentGame; TabGame *parentGame;
@ -95,6 +95,7 @@ private slots:
void loadLocalDeck(); void loadLocalDeck();
void loadRemoteDeck(); void loadRemoteDeck();
void readyStart(); void readyStart();
void forceStart();
void deckSelectFinished(const Response &r); void deckSelectFinished(const Response &r);
void sideboardPlanChanged(); void sideboardPlanChanged();
void sideboardLockButtonClicked(); void sideboardLockButtonClicked();

View file

@ -5,4 +5,5 @@ message Command_ReadyStart {
optional Command_ReadyStart ext = 1016; optional Command_ReadyStart ext = 1016;
} }
optional bool ready = 1; optional bool ready = 1;
optional bool force_start = 2;
} }

View file

@ -81,7 +81,7 @@ Server_Game::Server_Game(const ServerInfo_User &_creatorInfo,
currentReplay->set_replay_id(room->getServer()->getDatabaseInterface()->getNextReplayId()); currentReplay->set_replay_id(room->getServer()->getDatabaseInterface()->getNextReplayId());
description = _description.simplified(); description = _description.simplified();
connect(this, SIGNAL(sigStartGameIfReady()), this, SLOT(doStartGameIfReady()), Qt::QueuedConnection); connect(this, &Server_Game::sigStartGameIfReady, this, &Server_Game::doStartGameIfReady, Qt::QueuedConnection);
getInfo(*currentReplay->mutable_game_info()); getInfo(*currentReplay->mutable_game_info());
@ -311,20 +311,31 @@ void Server_Game::sendGameStateToPlayers()
} }
} }
void Server_Game::doStartGameIfReady() void Server_Game::doStartGameIfReady(bool forceStartGame)
{ {
Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface(); Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface();
QMutexLocker locker(&gameMutex); QMutexLocker locker(&gameMutex);
if (getPlayerCount() < maxPlayers) if (getPlayerCount() < maxPlayers && !forceStartGame) {
return; return;
for (Server_Player *player : players.values()) {
if (!player->getReadyStart() && !player->getSpectator())
return;
} }
for (Server_Player *player : players.values()) { for (Server_Player *player : players.values()) {
if (!player->getSpectator()) if (!player->getReadyStart() && !player->getSpectator()) {
if (forceStartGame) {
// Player is not ready to start, so kick them
// TODO: Move them to Spectators instead
kickPlayer(player->getPlayerId());
} else {
return;
}
}
}
for (Server_Player *player : players.values()) {
if (!player->getSpectator()) {
player->setupZones(); player->setupZones();
}
} }
gameStarted = true; gameStarted = true;
@ -369,9 +380,9 @@ void Server_Game::doStartGameIfReady()
emit gameInfoChanged(gameInfo); emit gameInfoChanged(gameInfo);
} }
void Server_Game::startGameIfReady() void Server_Game::startGameIfReady(bool forceStartGame)
{ {
emit sigStartGameIfReady(); emit sigStartGameIfReady(forceStartGame);
} }
void Server_Game::stopGameIfFinished() void Server_Game::stopGameIfFinished()

View file

@ -82,11 +82,11 @@ private:
bool withUserInfo); bool withUserInfo);
void storeGameInformation(); void storeGameInformation();
signals: signals:
void sigStartGameIfReady(); void sigStartGameIfReady(bool override);
void gameInfoChanged(ServerInfo_Game gameInfo); void gameInfoChanged(ServerInfo_Game gameInfo);
private slots: private slots:
void pingClockTimeout(); void pingClockTimeout();
void doStartGameIfReady(); void doStartGameIfReady(bool forceStartGame = false);
public: public:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
@ -180,7 +180,7 @@ public:
void removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Player *player); void removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Player *player);
void unattachCards(GameEventStorage &ges, Server_Player *player); void unattachCards(GameEventStorage &ges, Server_Player *player);
bool kickPlayer(int playerId); bool kickPlayer(int playerId);
void startGameIfReady(); void startGameIfReady(bool forceStartGame);
void stopGameIfFinished(); void stopGameIfFinished();
int getActivePlayer() const int getActivePlayer() const
{ {

View file

@ -944,7 +944,7 @@ Server_Player::cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer &
return Response::RespContextError; return Response::RespContextError;
} }
if (readyStart == cmd.ready()) { if (readyStart == cmd.ready() && !cmd.force_start()) {
return Response::RespContextError; return Response::RespContextError;
} }
@ -955,8 +955,13 @@ Server_Player::cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer &
ges.enqueueGameEvent(event, playerId); ges.enqueueGameEvent(event, playerId);
ges.setGameEventContext(Context_ReadyStart()); ges.setGameEventContext(Context_ReadyStart());
if (cmd.ready()) { if (cmd.force_start()) {
game->startGameIfReady(); if (game->getHostId() != playerId) {
return Response::RespFunctionNotAllowed;
}
game->startGameIfReady(true);
} else if (cmd.ready()) {
game->startGameIfReady(false);
} }
return Response::RespOk; return Response::RespOk;