changed leave game shortcut, server cleanups, added max_games_per_user

This commit is contained in:
Max-Wilhelm Bruker 2011-04-21 01:52:09 +02:00
parent d0b8c6ebd9
commit 38b31681e2
11 changed files with 85 additions and 64 deletions

View file

@ -296,7 +296,7 @@ void TabGame::retranslateUi()
aConcede->setText(tr("&Concede"));
aConcede->setShortcut(tr("F2"));
aLeaveGame->setText(tr("&Leave game"));
aLeaveGame->setShortcut(tr("Esc"));
aLeaveGame->setShortcut(tr("Ctrl+Q"));
sayLabel->setText(tr("&Say:"));
cardInfo->retranslateUi();

View file

@ -112,24 +112,28 @@ void Server::broadcastRoomUpdate()
delete event;
}
void Server::gameCreated(Server_Game *game)
{
QMutexLocker locker(&serverMutex);
games.insert(game->getGameId(), game);
}
void Server::gameClosing(int gameId)
{
QMutexLocker locker(&serverMutex);
qDebug("Server::gameClosing");
games.remove(gameId);
}
void Server::addRoom(Server_Room *newRoom)
{
QMutexLocker locker(&serverMutex);
rooms.insert(newRoom->getId(), newRoom);
connect(newRoom, SIGNAL(roomInfoChanged()), this, SLOT(broadcastRoomUpdate()));
connect(newRoom, SIGNAL(gameCreated(Server_Game *)), this, SLOT(gameCreated(Server_Game *)));
connect(newRoom, SIGNAL(gameClosing(int)), this, SLOT(gameClosing(int)));
}
int Server::getUsersCount() const
{
QMutexLocker locker(&serverMutex);
return users.size();
}
int Server::getGamesCount() const
{
int result = 0;
QMutexLocker locker(&serverMutex);
QMapIterator<int, Server_Room *> roomIterator(rooms);
while (roomIterator.hasNext()) {
Server_Room *room = roomIterator.next().value();
QMutexLocker roomLocker(&room->roomMutex);
result += room->getGames().size();
}
return result;
}

View file

@ -19,15 +19,12 @@ class Server : public QObject
signals:
void pingClockTimeout();
private slots:
void gameCreated(Server_Game *game);
void gameClosing(int gameId);
void broadcastRoomUpdate();
public:
mutable QMutex serverMutex;
Server(QObject *parent = 0);
~Server();
AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password);
QList<Server_Game *> getGames() const { return games.values(); }
const QMap<int, Server_Room *> &getRooms() { return rooms; }
int getNextGameId() { return nextGameId++; }
@ -42,12 +39,12 @@ public:
virtual int getMessageCountingInterval() const { return 0; }
virtual int getMaxMessageCountPerInterval() const { return 0; }
virtual int getMaxMessageSizePerInterval() const { return 0; }
virtual int getMaxGamesPerUser() const { return 0; }
virtual QMap<QString, ServerInfo_User *> getBuddyList(const QString &name) = 0;
virtual QMap<QString, ServerInfo_User *> getIgnoreList(const QString &name) = 0;
virtual bool getUserBanned(Server_ProtocolHandler * /*client*/, const QString & /*userName*/) const { return false; }
protected:
QMap<int, Server_Game *> games;
QList<Server_ProtocolHandler *> clients;
QMap<QString, Server_ProtocolHandler *> users;
QMap<int, Server_Room *> rooms;
@ -55,6 +52,8 @@ protected:
virtual bool userExists(const QString &user) = 0;
virtual AuthenticationResult checkUserPassword(const QString &user, const QString &password) = 0;
virtual ServerInfo_User *getUserData(const QString &name) = 0;
int getUsersCount() const;
int getGamesCount() const;
int nextGameId;
void addRoom(Server_Room *newRoom);
};

View file

@ -44,6 +44,7 @@ Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QS
Server_Game::~Server_Game()
{
QMutexLocker roomLocker(&room->roomMutex);
QMutexLocker locker(&gameMutex);
sendGameEvent(new Event_GameClosed);
@ -53,7 +54,7 @@ Server_Game::~Server_Game()
delete playerIterator.next().value();
players.clear();
emit gameClosing();
room->removeGame(this);
delete creatorInfo;
qDebug("Server_Game destructor");
}
@ -233,6 +234,7 @@ Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spec
void Server_Game::removePlayer(Server_Player *player)
{
QMutexLocker roomLocker(&room->roomMutex);
QMutexLocker locker(&gameMutex);
players.remove(player->getPlayerId());
@ -281,6 +283,7 @@ void Server_Game::removeArrowsToPlayer(Server_Player *player)
bool Server_Game::kickPlayer(int playerId)
{
QMutexLocker roomLocker(&room->roomMutex);
QMutexLocker locker(&gameMutex);
Server_Player *playerToKick = players.value(playerId);

View file

@ -53,7 +53,6 @@ private:
int secondsElapsed;
QTimer *pingClock;
signals:
void gameClosing();
void sigStartGameIfReady();
private slots:
void pingClockTimeout();

View file

@ -276,36 +276,20 @@ ResponseCode Server_ProtocolHandler::cmdLogin(Command_Login *cmd, CommandContain
enqueueProtocolItem(new Event_ServerMessage(server->getLoginMessage()));
QList<ServerInfo_User *> _buddyList, _ignoreList;
if (authState == PasswordRight) {
buddyList = server->getBuddyList(userInfo->getName());
ignoreList = server->getIgnoreList(userInfo->getName());
// This might not scale very well. Use an extra QMap if it becomes a problem.
QMutexLocker serverLocker(&server->serverMutex);
QMutexLocker gameListLocker(&gameListMutex);
const QList<Server_Game *> &serverGames = server->getGames();
for (int i = 0; i < serverGames.size(); ++i) {
QMutexLocker gameLocker(&serverGames[i]->gameMutex);
const QList<Server_Player *> &gamePlayers = serverGames[i]->getPlayers().values();
for (int j = 0; j < gamePlayers.size(); ++j)
if (gamePlayers[j]->getUserInfo()->getName() == userInfo->getName()) {
gamePlayers[j]->setProtocolHandler(this);
games.insert(serverGames[i]->getGameId(), QPair<Server_Game *, Server_Player *>(serverGames[i], gamePlayers[j]));
enqueueProtocolItem(new Event_GameJoined(serverGames[i]->getGameId(), serverGames[i]->getDescription(), gamePlayers[j]->getPlayerId(), gamePlayers[j]->getSpectator(), serverGames[i]->getSpectatorsCanTalk(), serverGames[i]->getSpectatorsSeeEverything(), true));
enqueueProtocolItem(GameEventContainer::makeNew(new Event_GameStateChanged(serverGames[i]->getGameStarted(), serverGames[i]->getActivePlayer(), serverGames[i]->getActivePhase(), serverGames[i]->getGameState(gamePlayers[j])), serverGames[i]->getGameId()));
}
}
}
QList<ServerInfo_User *> _buddyList;
QMapIterator<QString, ServerInfo_User *> buddyIterator(buddyList);
while (buddyIterator.hasNext())
_buddyList.append(new ServerInfo_User(buddyIterator.next().value()));
QList<ServerInfo_User *> _ignoreList;
ignoreList = server->getIgnoreList(userInfo->getName());
QMapIterator<QString, ServerInfo_User *> ignoreIterator(ignoreList);
while (ignoreIterator.hasNext())
_ignoreList.append(new ServerInfo_User(ignoreIterator.next().value()));
}
cont->setResponse(new Response_Login(cont->getCmdId(), RespOk, new ServerInfo_User(userInfo, true), _buddyList, _ignoreList));
return RespNothing;
@ -374,11 +358,31 @@ ResponseCode Server_ProtocolHandler::cmdJoinRoom(Command_JoinRoom *cmd, CommandC
if (!r)
return RespNameNotFound;
QMutexLocker roomLocker(&r->roomMutex);
r->addClient(this);
rooms.insert(r->getId(), r);
enqueueProtocolItem(new Event_RoomSay(r->getId(), QString(), r->getJoinMessage()));
// This might not scale very well. Use an extra QMap if it becomes a problem.
QMutexLocker gameListLocker(&gameListMutex);
QMapIterator<int, Server_Game *> gameIterator(r->getGames());
while (gameIterator.hasNext()) {
Server_Game *game = gameIterator.next().value();
QMutexLocker gameLocker(&game->gameMutex);
const QList<Server_Player *> &gamePlayers = game->getPlayers().values();
for (int j = 0; j < gamePlayers.size(); ++j)
if (gamePlayers[j]->getUserInfo()->getName() == userInfo->getName()) {
gamePlayers[j]->setProtocolHandler(this);
games.insert(game->getGameId(), QPair<Server_Game *, Server_Player *>(game, gamePlayers[j]));
enqueueProtocolItem(new Event_GameJoined(game->getGameId(), game->getDescription(), gamePlayers[j]->getPlayerId(), gamePlayers[j]->getSpectator(), game->getSpectatorsCanTalk(), game->getSpectatorsSeeEverything(), true));
enqueueProtocolItem(GameEventContainer::makeNew(new Event_GameStateChanged(game->getGameStarted(), game->getActivePlayer(), game->getActivePhase(), game->getGameState(gamePlayers[j])), game->getGameId()));
break;
}
}
cont->setResponse(new Response_JoinRoom(cont->getCmdId(), RespOk, r->getInfo(true)));
return RespNothing;
}
@ -437,6 +441,10 @@ ResponseCode Server_ProtocolHandler::cmdCreateGame(Command_CreateGame *cmd, Comm
if (authState == PasswordWrong)
return RespLoginNeeded;
if (server->getMaxGamesPerUser() > 0)
if (room->getGamesCreatedByUser(userInfo->getName()) >= server->getMaxGamesPerUser())
return RespContextError;
QList<int> gameTypes;
QList<GameTypeId *> gameTypeList = cmd->getGameTypes();
for (int i = 0; i < gameTypeList.size(); ++i)

View file

@ -87,26 +87,33 @@ Server_Game *Server_Room::createGame(const QString &description, const QString &
// This mutex needs to be unlocked by the caller.
newGame->gameMutex.lock();
games.insert(newGame->getGameId(), newGame);
connect(newGame, SIGNAL(gameClosing()), this, SLOT(removeGame()));
broadcastGameListUpdate(newGame);
emit gameCreated(newGame);
emit roomInfoChanged();
return newGame;
}
void Server_Room::removeGame()
void Server_Room::removeGame(Server_Game *game)
{
QMutexLocker locker(&roomMutex);
Server_Game *game = static_cast<Server_Game *>(sender());
QMutexLocker gameLocker(&game->gameMutex);
// No need to lock roomMutex or gameMutex. This method is only
// called from ~Server_Game, which locks both mutexes anyway beforehand.
broadcastGameListUpdate(game);
games.remove(game->getGameId());
emit gameClosing(game->getGameId());
emit roomInfoChanged();
}
int Server_Room::getGamesCreatedByUser(const QString &userName) const
{
QMutexLocker locker(&roomMutex);
QMapIterator<int, Server_Game *> gamesIterator(games);
int result = 0;
while (gamesIterator.hasNext())
if (gamesIterator.next().value()->getCreatorInfo()->getName() == userName)
++result;
return result;
}

View file

@ -18,8 +18,6 @@ class Server_Room : public QObject, public QList<Server_ProtocolHandler *> {
Q_OBJECT
signals:
void roomInfoChanged();
void gameCreated(Server_Game *game);
void gameClosing(int gameId);
private:
int id;
QString name;
@ -28,8 +26,6 @@ private:
QString joinMessage;
QStringList gameTypes;
QMap<int, Server_Game *> games;
private slots:
void removeGame();
public:
mutable QMutex roomMutex;
Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent);
@ -41,12 +37,14 @@ public:
const QMap<int, Server_Game *> &getGames() const { return games; }
Server *getServer() const;
ServerInfo_Room *getInfo(bool complete) const;
int getGamesCreatedByUser(const QString &name) const;
void addClient(Server_ProtocolHandler *client);
void removeClient(Server_ProtocolHandler *client);
void say(Server_ProtocolHandler *client, const QString &s);
void broadcastGameListUpdate(Server_Game *game);
Server_Game *createGame(const QString &description, const QString &password, int maxPlayers, const QList<int> &_gameTypes, bool onlyBuddies, bool onlyRegistered, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator);
void removeGame(Server_Game *game);
void sendRoomEvent(RoomEvent *event);
};

View file

@ -35,3 +35,4 @@ max_users_per_address=4
message_counting_interval=10
max_message_size_per_interval=1000
max_message_count_per_interval=10
max_games_per_user=5

View file

@ -102,6 +102,7 @@ Servatrice::Servatrice(QSettings *_settings, QObject *parent)
messageCountingInterval = settings->value("security/message_counting_interval").toInt();
maxMessageCountPerInterval = settings->value("security/max_message_count_per_interval").toInt();
maxMessageSizePerInterval = settings->value("security/max_message_size_per_interval").toInt();
maxGamesPerUser = settings->value("security/max_games_per_user").toInt();
}
Servatrice::~Servatrice()
@ -357,9 +358,9 @@ void Servatrice::statusUpdate()
query.prepare("insert into " + dbPrefix + "_uptime (id_server, timest, uptime, users_count, games_count) values(:id, NOW(), :uptime, :users_count, :games_count)");
query.bindValue(":id", serverId);
query.bindValue(":uptime", uptime);
query.bindValue(":users_count", users.size());
query.bindValue(":games_count", games.size());
query.bindValue(":users_count", getUsersCount());
query.bindValue(":games_count", getGamesCount());
execSqlQuery(query);
}
const QString Servatrice::versionString = "Servatrice 0.20110406";
const QString Servatrice::versionString = "Servatrice 0.20110421";

View file

@ -65,6 +65,7 @@ public:
int getMessageCountingInterval() const { return messageCountingInterval; }
int getMaxMessageCountPerInterval() const { return maxMessageCountPerInterval; }
int getMaxMessageSizePerInterval() const { return maxMessageSizePerInterval; }
int getMaxGamesPerUser() const { return maxGamesPerUser; }
QString getDbPrefix() const { return dbPrefix; }
void updateLoginMessage();
ServerInfo_User *getUserData(const QString &name);
@ -88,7 +89,7 @@ private:
QList<QPair<QHostAddress, int> > addressBanList;
QList<QPair<QString, int> > nameBanList;
int maxGameInactivityTime, maxPlayerInactivityTime;
int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval;
int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser;
ServerInfo_User *evalUserQueryResult(const QSqlQuery &query, bool complete);
};