diff --git a/common/pb/event_game_joined.proto b/common/pb/event_game_joined.proto index 67ea2a41..37cbd865 100644 --- a/common/pb/event_game_joined.proto +++ b/common/pb/event_game_joined.proto @@ -4,12 +4,13 @@ message Event_GameJoined { extend SessionEvent { optional Event_GameJoined ext = 1009; } - optional sint32 game_id = 1; - optional string game_description = 2; - optional sint32 host_id = 3; - optional sint32 player_id = 4; - optional bool spectator = 5; - optional bool spectators_can_talk = 6; - optional bool spectators_see_everything = 7; - optional bool resuming = 8; + optional sint32 room_id = 1; + optional sint32 game_id = 2; + optional string game_description = 3; + optional sint32 host_id = 4; + optional sint32 player_id = 5; + optional bool spectator = 6; + optional bool spectators_can_talk = 7; + optional bool spectators_see_everything = 8; + optional bool resuming = 9; } diff --git a/common/pb/isl_message.proto b/common/pb/isl_message.proto index 790c333e..20dec29d 100644 --- a/common/pb/isl_message.proto +++ b/common/pb/isl_message.proto @@ -6,19 +6,24 @@ import "room_event.proto"; message IslMessage { enum MessageType { - RESPONSE = 0; - SESSION_EVENT = 1; - GAME_COMMAND_CONTAINER = 2; - GAME_EVENT_CONTAINER = 3; - ROOM_EVENT = 4; + GAME_COMMAND_CONTAINER = 0; + ROOM_COMMAND_CONTAINER = 1; + + RESPONSE = 10; + SESSION_EVENT = 11; + GAME_EVENT_CONTAINER = 12; + ROOM_EVENT = 13; } optional MessageType message_type = 1; - optional sint32 game_id = 10; + optional uint64 session_id = 9; + optional sint32 player_id = 10 [default = -1]; - optional Response response = 100; - optional SessionEvent session_event = 101; - optional CommandContainer game_command = 102; - optional GameEventContainer game_event_container = 103; - optional RoomEvent room_event = 104; + optional CommandContainer game_command = 100; + optional CommandContainer room_command = 101; + + optional Response response = 200; + optional SessionEvent session_event = 201; + optional GameEventContainer game_event_container = 202; + optional RoomEvent room_event = 203; } diff --git a/common/pb/serverinfo_user.proto b/common/pb/serverinfo_user.proto index 2dcc58bb..267ac3f2 100644 --- a/common/pb/serverinfo_user.proto +++ b/common/pb/serverinfo_user.proto @@ -20,4 +20,5 @@ message ServerInfo_User { optional bytes avatar_bmp = 7; optional sint32 id = 8 [default = -1]; optional sint32 server_id = 9 [default = -1]; + optional uint64 session_id = 10; } diff --git a/common/server.cpp b/common/server.cpp index 33dfe8a5..f351f190 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -23,6 +23,7 @@ #include "server_room.h" #include "server_protocolhandler.h" #include "server_remoteuserinterface.h" +#include "server_metatypes.h" #include "pb/event_user_joined.pb.h" #include "pb/event_user_left.pb.h" #include "pb/event_list_rooms.pb.h" @@ -37,6 +38,13 @@ Server::Server(QObject *parent) qRegisterMetaType("ServerInfo_Game"); qRegisterMetaType("ServerInfo_Room"); qRegisterMetaType("ServerInfo_User"); + qRegisterMetaType("CommandContainer"); + qRegisterMetaType("Response"); + qRegisterMetaType("GameEventContainer"); + qRegisterMetaType("IslMessage"); + qRegisterMetaType("Command_JoinGame"); + + connect(this, SIGNAL(sigSendIslMessage(IslMessage, int)), this, SLOT(doSendIslMessage(IslMessage, int)), Qt::QueuedConnection); } Server::~Server() @@ -92,15 +100,16 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString data.set_name(name.toStdString()); } - session->setUserInfo(data); - users.insert(name, session); qDebug() << "Server::loginUser: name=" << name; - session->setSessionId(startSession(name, session->getAddress())); + data.set_session_id(startSession(name, session->getAddress())); unlockSessionTables(); - qDebug() << "session id:" << session->getSessionId(); + usersBySessionId.insert(data.session_id(), session); + + qDebug() << "session id:" << data.session_id(); + session->setUserInfo(data); Event_UserJoined event; event.mutable_user_info()->CopyFrom(session->copyUserInfo(false)); @@ -108,9 +117,13 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString for (int i = 0; i < clients.size(); ++i) if (clients[i]->getAcceptsUserListChanges()) clients[i]->sendProtocolItem(*se); + delete se; + + event.mutable_user_info()->CopyFrom(session->copyUserInfo(true, true)); locker.unlock(); - sendIslMessage(*se); + se = Server_ProtocolHandler::prepareSessionEvent(event); + sendIsl_SessionEvent(*se); delete se; return authState; @@ -120,6 +133,7 @@ void Server::addClient(Server_ProtocolHandler *client) { QWriteLocker locker(&clientsLock); clients << client; + connect(client, SIGNAL(logDebugMessage(QString, void *)), this, SIGNAL(logDebugMessage(QString, void *))); } void Server::removeClient(Server_ProtocolHandler *client) @@ -134,15 +148,18 @@ void Server::removeClient(Server_ProtocolHandler *client) for (int i = 0; i < clients.size(); ++i) if (clients[i]->getAcceptsUserListChanges()) clients[i]->sendProtocolItem(*se); - sendIslMessage(*se); + sendIsl_SessionEvent(*se); delete se; users.remove(QString::fromStdString(data->name())); qDebug() << "Server::removeClient: name=" << QString::fromStdString(data->name()); - if (client->getSessionId() != -1) - endSession(client->getSessionId()); - qDebug() << "closed session id:" << client->getSessionId(); + if (data->has_session_id()) { + const qint64 sessionId = data->session_id(); + usersBySessionId.remove(sessionId); + endSession(sessionId); + qDebug() << "closed session id:" << sessionId; + } } qDebug() << "Server::removeClient:" << clients.size() << "clients; " << users.size() << "users left"; } @@ -152,7 +169,9 @@ void Server::externalUserJoined(const ServerInfo_User &userInfo) // This function is always called from the main thread via signal/slot. QWriteLocker locker(&clientsLock); - externalUsers.insert(QString::fromStdString(userInfo.name()), new Server_RemoteUserInterface(this, ServerInfo_User_Container(userInfo))); + Server_RemoteUserInterface *newUser = new Server_RemoteUserInterface(this, ServerInfo_User_Container(userInfo)); + externalUsers.insert(QString::fromStdString(userInfo.name()), newUser); + externalUsersBySessionId.insert(userInfo.session_id(), newUser); Event_UserJoined event; event.mutable_user_info()->CopyFrom(userInfo); @@ -169,7 +188,9 @@ void Server::externalUserLeft(const QString &userName) // This function is always called from the main thread via signal/slot. QWriteLocker locker(&clientsLock); - delete externalUsers.take(userName); + Server_AbstractUserInterface *user = externalUsers.take(userName); + externalUsersBySessionId.remove(user->getUserInfo()->session_id()); + delete user; Event_UserLeft event; event.set_name(userName.toStdString()); @@ -233,8 +254,124 @@ void Server::externalRoomGameListChanged(int roomId, const ServerInfo_Game &game room->updateExternalGameList(gameInfo); } +void Server::externalJoinGameCommandReceived(const Command_JoinGame &cmd, int cmdId, int roomId, int serverId, qint64 sessionId) +{ + // This function is always called from the main thread via signal/slot. + + try { + QReadLocker roomsLocker(&roomsLock); + QReadLocker clientsLocker(&clientsLock); + + Server_Room *room = rooms.value(roomId); + if (!room) { + qDebug() << "externalJoinGameCommandReceived: room id=" << roomId << "not found"; + throw Response::RespNotInRoom; + } + Server_AbstractUserInterface *userInterface = externalUsersBySessionId.value(sessionId); + if (!userInterface) { + qDebug() << "externalJoinGameCommandReceived: session id=" << sessionId << "not found"; + throw Response::RespNotInRoom; + } + + ResponseContainer responseContainer(cmdId); + Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface); + userInterface->sendResponseContainer(responseContainer, responseCode); + } catch (Response::ResponseCode code) { + Response response; + response.set_cmd_id(cmdId); + response.set_response_code(code); + + sendIsl_Response(response, serverId, sessionId); + } +} + +void Server::externalGameCommandContainerReceived(const CommandContainer &cont, int playerId, int serverId, qint64 sessionId) +{ + // This function is always called from the main thread via signal/slot. + + try { + ResponseContainer responseContainer(cont.cmd_id()); + Response::ResponseCode finalResponseCode = Response::RespOk; + + QReadLocker roomsLocker(&roomsLock); + Server_Room *room = rooms.value(cont.room_id()); + if (!room) { + qDebug() << "externalGameCommandContainerReceived: room id=" << cont.room_id() << "not found"; + throw Response::RespNotInRoom; + } + + QMutexLocker roomGamesLocker(&room->gamesMutex); + Server_Game *game = room->getGames().value(cont.game_id()); + if (!game) { + qDebug() << "externalGameCommandContainerReceived: game id=" << cont.game_id() << "not found"; + throw Response::RespNotInRoom; + } + + QMutexLocker gameLocker(&game->gameMutex); + Server_Player *player = game->getPlayer(playerId); + if (!player) { + qDebug() << "externalGameCommandContainerReceived: player id=" << playerId << "not found"; + throw Response::RespNotInRoom; + } + + GameEventStorage ges; + for (int i = cont.game_command_size() - 1; i >= 0; --i) { + const GameCommand &sc = cont.game_command(i); + qDebug() << "[ISL]" << QString::fromStdString(sc.ShortDebugString()); + + Response::ResponseCode resp = player->processGameCommand(sc, responseContainer, ges); + + if (resp != Response::RespOk) + finalResponseCode = resp; + } + ges.sendToGame(game); + + if (finalResponseCode != Response::RespNothing) { + player->playerMutex.lock(); + player->getUserInterface()->sendResponseContainer(responseContainer, finalResponseCode); + player->playerMutex.unlock(); + } + } catch (Response::ResponseCode code) { + Response response; + response.set_cmd_id(cont.cmd_id()); + response.set_response_code(code); + + sendIsl_Response(response, serverId, sessionId); + } +} + +void Server::externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId) +{ + // This function is always called from the main thread via signal/slot. + + QReadLocker usersLocker(&clientsLock); + + Server_ProtocolHandler *client = usersBySessionId.value(sessionId); + if (!client) { + qDebug() << "externalGameEventContainerReceived: session" << sessionId << "not found"; + return; + } + client->sendProtocolItem(cont); +} + +void Server::externalResponseReceived(const Response &resp, qint64 sessionId) +{ + // This function is always called from the main thread via signal/slot. + + QReadLocker usersLocker(&clientsLock); + + Server_ProtocolHandler *client = usersBySessionId.value(sessionId); + if (!client) { + qDebug() << "externalResponseReceived: session" << sessionId << "not found"; + return; + } + client->sendProtocolItem(resp); +} + void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl) { + // This function is always called from the main thread via signal/slot. + Event_ListRooms event; event.add_room_list()->CopyFrom(roomInfo); @@ -247,7 +384,7 @@ void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl clientsLock.unlock(); if (sendToIsl) - sendIslMessage(*se); + sendIsl_SessionEvent(*se); delete se; } @@ -279,38 +416,73 @@ int Server::getGamesCount() const return result; } -void Server::sendIslMessage(const Response &item, int serverId) +void Server::sendIsl_Response(const Response &item, int serverId, qint64 sessionId) { IslMessage msg; msg.set_message_type(IslMessage::RESPONSE); + if (sessionId != -1) + msg.set_session_id(sessionId); msg.mutable_response()->CopyFrom(item); - doSendIslMessage(msg, serverId); + emit sigSendIslMessage(msg, serverId); } -void Server::sendIslMessage(const SessionEvent &item, int serverId) +void Server::sendIsl_SessionEvent(const SessionEvent &item, int serverId, qint64 sessionId) { IslMessage msg; msg.set_message_type(IslMessage::SESSION_EVENT); + if (sessionId != -1) + msg.set_session_id(sessionId); msg.mutable_session_event()->CopyFrom(item); - doSendIslMessage(msg, serverId); + emit sigSendIslMessage(msg, serverId); } -void Server::sendIslMessage(const GameEventContainer &item, int serverId) +void Server::sendIsl_GameEventContainer(const GameEventContainer &item, int serverId, qint64 sessionId) { IslMessage msg; msg.set_message_type(IslMessage::GAME_EVENT_CONTAINER); + if (sessionId != -1) + msg.set_session_id(sessionId); msg.mutable_game_event_container()->CopyFrom(item); - doSendIslMessage(msg, serverId); + emit sigSendIslMessage(msg, serverId); } -void Server::sendIslMessage(const RoomEvent &item, int serverId) +void Server::sendIsl_RoomEvent(const RoomEvent &item, int serverId, qint64 sessionId) { IslMessage msg; msg.set_message_type(IslMessage::ROOM_EVENT); + if (sessionId != -1) + msg.set_session_id(sessionId); msg.mutable_room_event()->CopyFrom(item); - doSendIslMessage(msg, serverId); + emit sigSendIslMessage(msg, serverId); +} + +void Server::sendIsl_GameCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId, int playerId) +{ + IslMessage msg; + msg.set_message_type(IslMessage::GAME_COMMAND_CONTAINER); + msg.set_session_id(sessionId); + msg.set_player_id(playerId); + + CommandContainer *cont = msg.mutable_game_command(); + cont->CopyFrom(item); + cont->set_room_id(roomId); + + emit sigSendIslMessage(msg, serverId); +} + +void Server::sendIsl_RoomCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId) +{ + IslMessage msg; + msg.set_message_type(IslMessage::ROOM_COMMAND_CONTAINER); + msg.set_session_id(sessionId); + + CommandContainer *cont = msg.mutable_room_command(); + cont->CopyFrom(item); + cont->set_room_id(roomId); + + emit sigSendIslMessage(msg, serverId); } diff --git a/common/server.h b/common/server.h index 8d937cad..6ef9d654 100644 --- a/common/server.h +++ b/common/server.h @@ -6,10 +6,7 @@ #include #include #include -#include #include "pb/serverinfo_user.pb.h" -#include "pb/serverinfo_room.pb.h" -#include "pb/serverinfo_game.pb.h" class Server_Game; class Server_Room; @@ -17,11 +14,15 @@ class Server_ProtocolHandler; class Server_AbstractUserInterface; class GameReplay; class IslMessage; -class Response; class SessionEvent; -class GameEventContainer; class RoomEvent; class DeckList; +class ServerInfo_Game; +class ServerInfo_Room; +class Response; +class GameEventContainer; +class CommandContainer; +class Command_JoinGame; enum AuthenticationResult { NotLoggedIn = 0, PasswordRight = 1, UnknownUser = 2, WouldOverwriteOldSession = 3, UserIsBanned = 4 }; @@ -30,10 +31,12 @@ class Server : public QObject Q_OBJECT signals: void pingClockTimeout(); + void sigSendIslMessage(const IslMessage &message, int serverId); + void logDebugMessage(QString message, void *caller); private slots: void broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl = false); public: - mutable QReadWriteLock clientsLock, roomsLock; + mutable QReadWriteLock clientsLock, roomsLock; // locking order: roomsLock before clientsLock Server(QObject *parent = 0); ~Server(); AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reason); @@ -42,6 +45,7 @@ public: virtual int getNextReplayId() { return nextReplayId++; } const QMap &getUsers() const { return users; } + const QMap &getUsersBySessionId() const { return usersBySessionId; } void addClient(Server_ProtocolHandler *player); void removeClient(Server_ProtocolHandler *player); virtual QString getLoginMessage() const { return QString(); } @@ -63,10 +67,12 @@ public: virtual void storeGameInformation(int secondsElapsed, const QSet &allPlayersEver, const QSet &allSpectatorsEver, const QList &replays) { } virtual DeckList *getDeckFromDatabase(int deckId, const QString &userName) { return 0; } - void sendIslMessage(const Response &item, int serverId = -1); - void sendIslMessage(const SessionEvent &item, int serverId = -1); - void sendIslMessage(const GameEventContainer &item, int serverId = -1); - void sendIslMessage(const RoomEvent &item, int serverId = -1); + void sendIsl_Response(const Response &item, int serverId = -1, qint64 sessionId = -1); + void sendIsl_SessionEvent(const SessionEvent &item, int serverId = -1, qint64 sessionId = -1); + void sendIsl_GameEventContainer(const GameEventContainer &item, int serverId = -1, qint64 sessionId = -1); + void sendIsl_RoomEvent(const RoomEvent &item, int serverId = -1, qint64 sessionId = -1); + void sendIsl_GameCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId, int playerId); + void sendIsl_RoomCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId); void addExternalUser(const ServerInfo_User &userInfo); void removeExternalUser(const QString &userName); @@ -78,15 +84,23 @@ protected slots: void externalRoomUserLeft(int roomId, const QString &userName); void externalRoomSay(int roomId, const QString &userName, const QString &message); void externalRoomGameListChanged(int roomId, const ServerInfo_Game &gameInfo); + void externalJoinGameCommandReceived(const Command_JoinGame &cmd, int cmdId, int roomId, int serverId, qint64 sessionId); + void externalGameCommandContainerReceived(const CommandContainer &cont, int playerId, int serverId, qint64 sessionId); + void externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId); + void externalResponseReceived(const Response &resp, qint64 sessionId); + + virtual void doSendIslMessage(const IslMessage &msg, int serverId) { } protected: void prepareDestroy(); QList clients; + QMap usersBySessionId; QMap users; + QMap externalUsersBySessionId; QMap externalUsers; QMap rooms; - virtual int startSession(const QString &userName, const QString &address) { return -1; } - virtual void endSession(int sessionId) { } + virtual qint64 startSession(const QString &userName, const QString &address) { return -1; } + virtual void endSession(qint64 sessionId) { } virtual bool userExists(const QString &user) { return false; } virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reason) { return UnknownUser; } virtual ServerInfo_User getUserData(const QString &name, bool withId = false) = 0; @@ -99,12 +113,6 @@ protected: virtual void lockSessionTables() { } virtual void unlockSessionTables() { } virtual bool userSessionExists(const QString &userName) { return false; } - - virtual void doSendIslMessage(const IslMessage &msg, int serverId) { } }; -Q_DECLARE_METATYPE(ServerInfo_User) -Q_DECLARE_METATYPE(ServerInfo_Room) -Q_DECLARE_METATYPE(ServerInfo_Game) - #endif diff --git a/common/server_abstractuserinterface.cpp b/common/server_abstractuserinterface.cpp index 30814950..ebd7d983 100644 --- a/common/server_abstractuserinterface.cpp +++ b/common/server_abstractuserinterface.cpp @@ -1,4 +1,7 @@ +#include +#include #include "server_abstractuserinterface.h" +#include "server_response_containers.h" #include void Server_AbstractUserInterface::sendProtocolItemByType(ServerMessage::MessageType type, const ::google::protobuf::Message &item) @@ -17,3 +20,22 @@ SessionEvent *Server_AbstractUserInterface::prepareSessionEvent(const ::google:: event->GetReflection()->MutableMessage(event, sessionEvent.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(sessionEvent); return event; } + +void Server_AbstractUserInterface::sendResponseContainer(const ResponseContainer &responseContainer, Response::ResponseCode responseCode) +{ + const QList > &preResponseQueue = responseContainer.getPreResponseQueue(); + for (int i = 0; i < preResponseQueue.size(); ++i) + sendProtocolItemByType(preResponseQueue[i].first, *preResponseQueue[i].second); + + Response response; + response.set_cmd_id(responseContainer.getCmdId()); + response.set_response_code(responseCode); + ::google::protobuf::Message *responseExtension = responseContainer.getResponseExtension(); + if (responseExtension) + response.GetReflection()->MutableMessage(&response, responseExtension->GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(*responseExtension); + sendProtocolItem(response); + + const QList > &postResponseQueue = responseContainer.getPostResponseQueue(); + for (int i = 0; i < postResponseQueue.size(); ++i) + sendProtocolItemByType(postResponseQueue[i].first, *postResponseQueue[i].second); +} diff --git a/common/server_abstractuserinterface.h b/common/server_abstractuserinterface.h index 6c6e3e23..b73b247b 100644 --- a/common/server_abstractuserinterface.h +++ b/common/server_abstractuserinterface.h @@ -3,13 +3,15 @@ #include "serverinfo_user_container.h" #include "pb/server_message.pb.h" +#include "pb/response.pb.h" -class Response; class SessionEvent; class GameEventContainer; class RoomEvent; +class ResponseContainer; class Server; +class Server_Game; class Server_AbstractUserInterface : public ServerInfo_User_Container { protected: @@ -19,6 +21,11 @@ public: Server_AbstractUserInterface(Server *_server, const ServerInfo_User_Container &other) : ServerInfo_User_Container(other), server(_server) { } virtual ~Server_AbstractUserInterface() { } + virtual int getLastCommandTime() const = 0; + + virtual void playerRemovedFromGame(Server_Game *game) = 0; + virtual void playerAddedToGame(int gameId, int roomId, int playerId) = 0; + virtual void sendProtocolItem(const Response &item) = 0; virtual void sendProtocolItem(const SessionEvent &item) = 0; virtual void sendProtocolItem(const GameEventContainer &item) = 0; @@ -26,6 +33,7 @@ public: void sendProtocolItemByType(ServerMessage::MessageType type, const ::google::protobuf::Message &item); static SessionEvent *prepareSessionEvent(const ::google::protobuf::Message &sessionEvent); + void sendResponseContainer(const ResponseContainer &responseContainer, Response::ResponseCode responseCode); }; #endif diff --git a/common/server_game.cpp b/common/server_game.cpp index 20461aff..587356e7 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -30,6 +30,7 @@ #include "pb/context_ping_changed.pb.h" #include "pb/event_player_properties_changed.pb.h" #include "pb/event_game_closed.pb.h" +#include "pb/event_game_joined.pb.h" #include "pb/event_game_host_changed.pb.h" #include "pb/event_game_state_changed.pb.h" #include "pb/event_kicked.pb.h" @@ -44,16 +45,37 @@ #include #include -Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *_room) - : QObject(), room(_room), hostId(0), creatorInfo(new ServerInfo_User(_creator->copyUserInfo(false))), gameStarted(false), gameId(_gameId), description(_description), password(_password), maxPlayers(_maxPlayers), gameTypes(_gameTypes), activePlayer(-1), activePhase(-1), onlyBuddies(_onlyBuddies), onlyRegistered(_onlyRegistered), spectatorsAllowed(_spectatorsAllowed), spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), inactivityCounter(0), startTimeOfThisGame(0), secondsElapsed(0), firstGameStarted(false), startTime(QDateTime::currentDateTime()), gameMutex(QMutex::Recursive) +Server_Game::Server_Game(const ServerInfo_User &_creatorInfo, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *_room) + : QObject(), + room(_room), + hostId(0), + creatorInfo(new ServerInfo_User(_creatorInfo)), + gameStarted(false), + gameId(_gameId), + description(_description), + password(_password), + maxPlayers(_maxPlayers), + gameTypes(_gameTypes), + activePlayer(-1), + activePhase(-1), + onlyBuddies(_onlyBuddies), + onlyRegistered(_onlyRegistered), + spectatorsAllowed(_spectatorsAllowed), + spectatorsNeedPassword(_spectatorsNeedPassword), + spectatorsCanTalk(_spectatorsCanTalk), + spectatorsSeeEverything(_spectatorsSeeEverything), + inactivityCounter(0), + startTimeOfThisGame(0), + secondsElapsed(0), + firstGameStarted(false), + startTime(QDateTime::currentDateTime()), + gameMutex(QMutex::Recursive) { currentReplay = new GameReplay; currentReplay->set_replay_id(room->getServer()->getNextReplayId()); connect(this, SIGNAL(sigStartGameIfReady()), this, SLOT(doStartGameIfReady()), Qt::QueuedConnection); - addPlayer(_creator, false, false); - currentReplay->mutable_game_info()->CopyFrom(getInfo()); if (room->getServer()->getGameShouldPing()) { @@ -112,8 +134,8 @@ void Server_Game::pingClockTimeout() const int oldPingTime = player->getPingTime(); player->playerMutex.lock(); int newPingTime; - if (player->getProtocolHandler()) - newPingTime = player->getProtocolHandler()->getLastCommandTime(); + if (player->getUserInterface()) + newPingTime = player->getUserInterface()->getLastCommandTime(); else newPingTime = -1; player->playerMutex.unlock(); @@ -345,14 +367,14 @@ bool Server_Game::containsUser(const QString &userName) const return false; } -Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spectator, bool broadcastUpdate) +void Server_Game::addPlayer(Server_AbstractUserInterface *userInterface, ResponseContainer &rc, bool spectator, bool broadcastUpdate) { QMutexLocker locker(&gameMutex); const QList &keyList = players.keys(); int playerId = keyList.isEmpty() ? 0 : (keyList.last() + 1); - Server_Player *newPlayer = new Server_Player(this, playerId, handler->copyUserInfo(true), spectator, handler); + Server_Player *newPlayer = new Server_Player(this, playerId, userInterface->copyUserInfo(true), spectator, userInterface); newPlayer->moveToThread(thread()); Event_Join joinEvent; @@ -368,11 +390,33 @@ Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spec hostId = playerId; sendGameEventContainer(prepareGameEvent(Event_GameHostChanged(), playerId)); } - + if (broadcastUpdate) emit gameInfoChanged(getInfo()); - return newPlayer; + userInterface->playerAddedToGame(gameId, room->getId(), newPlayer->getPlayerId()); + + Event_GameJoined event1; + event1.set_room_id(room->getId()); + event1.set_game_id(gameId); + event1.set_game_description(description.toStdString()); + event1.set_host_id(hostId); + event1.set_player_id(newPlayer->getPlayerId()); + event1.set_spectator(newPlayer->getSpectator()); + event1.set_spectators_can_talk(spectatorsCanTalk); + event1.set_spectators_see_everything(spectatorsSeeEverything); + event1.set_resuming(false); + rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, Server_AbstractUserInterface::prepareSessionEvent(event1)); + + Event_GameStateChanged event2; + QListIterator gameStateIterator(getGameState(newPlayer, false, true)); + while (gameStateIterator.hasNext()) + event2.add_player_list()->CopyFrom(gameStateIterator.next()); + event2.set_seconds_elapsed(secondsElapsed); + event2.set_game_started(gameStarted); + event2.set_active_player_id(activePlayer); + event2.set_active_phase(activePhase); + rc.enqueuePostResponseItem(ServerMessage::GAME_EVENT_CONTAINER, prepareGameEvent(event2, -1)); } void Server_Game::removePlayer(Server_Player *player) diff --git a/common/server_game.h b/common/server_game.h index be3c1c6e..1c27bada 100644 --- a/common/server_game.h +++ b/common/server_game.h @@ -73,7 +73,7 @@ private slots: void doStartGameIfReady(); public: mutable QMutex gameMutex; - Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *parent); + Server_Game(const ServerInfo_User &_creatorInfo, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *parent); ~Server_Game(); Server_Room *getRoom() const { return room; } ServerInfo_Game getInfo() const; @@ -94,7 +94,7 @@ public: bool getSpectatorsSeeEverything() const { return spectatorsSeeEverything; } Response::ResponseCode checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions); bool containsUser(const QString &userName) const; - Server_Player *addPlayer(Server_ProtocolHandler *handler, bool spectator, bool broadcastUpdate = true); + void addPlayer(Server_AbstractUserInterface *userInterface, ResponseContainer &rc, bool spectator, bool broadcastUpdate = true); void removePlayer(Server_Player *player); void removeArrowsToPlayer(GameEventStorage &ges, Server_Player *player); void unattachCards(GameEventStorage &ges, Server_Player *player); diff --git a/common/server_metatypes.h b/common/server_metatypes.h new file mode 100644 index 00000000..4266218e --- /dev/null +++ b/common/server_metatypes.h @@ -0,0 +1,24 @@ +#ifndef SERVER_METATYPES_H +#define SERVER_METATYPES_H + +#include + +#include "pb/serverinfo_user.pb.h" +#include "pb/serverinfo_room.pb.h" +#include "pb/serverinfo_game.pb.h" +#include "pb/commands.pb.h" +#include "pb/response.pb.h" +#include "pb/game_event_container.pb.h" +#include "pb/isl_message.pb.h" +#include "pb/room_commands.pb.h" + +Q_DECLARE_METATYPE(ServerInfo_User) +Q_DECLARE_METATYPE(ServerInfo_Room) +Q_DECLARE_METATYPE(ServerInfo_Game) +Q_DECLARE_METATYPE(CommandContainer) +Q_DECLARE_METATYPE(Response) +Q_DECLARE_METATYPE(GameEventContainer) +Q_DECLARE_METATYPE(IslMessage) +Q_DECLARE_METATYPE(Command_JoinGame) + +#endif diff --git a/common/server_player.cpp b/common/server_player.cpp index 969debd6..e707732b 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -1,3 +1,4 @@ +#include "server.h" #include "server_player.h" #include "server_card.h" #include "server_counter.h" @@ -5,7 +6,7 @@ #include "server_cardzone.h" #include "server_game.h" #include "server_room.h" -#include "server_protocolhandler.h" +#include "server_abstractuserinterface.h" #include "decklist.h" #include "color.h" #include "rng_abstract.h" @@ -76,8 +77,8 @@ #include -Server_Player::Server_Player(Server_Game *_game, int _playerId, const ServerInfo_User &_userInfo, bool _spectator, Server_ProtocolHandler *_handler) - : game(_game), handler(_handler), userInfo(new ServerInfo_User(_userInfo)), deck(0), pingTime(0), playerId(_playerId), spectator(_spectator), nextCardId(0), readyStart(false), conceded(false) +Server_Player::Server_Player(Server_Game *_game, int _playerId, const ServerInfo_User &_userInfo, bool _spectator, Server_AbstractUserInterface *_userInterface) + : game(_game), userInterface(_userInterface), userInfo(new ServerInfo_User(_userInfo)), deck(0), pingTime(0), playerId(_playerId), spectator(_spectator), nextCardId(0), readyStart(false), conceded(false) { } @@ -92,8 +93,8 @@ void Server_Player::prepareDestroy() delete deck; playerMutex.lock(); - if (handler) - handler->playerRemovedFromGame(game); + if (userInterface) + userInterface->playerRemovedFromGame(game); playerMutex.unlock(); delete userInfo; @@ -1557,17 +1558,17 @@ void Server_Player::sendGameEvent(const GameEventContainer &cont) { QMutexLocker locker(&playerMutex); - if (handler) - handler->sendProtocolItem(cont); + if (userInterface) + userInterface->sendProtocolItem(cont); } -void Server_Player::setProtocolHandler(Server_ProtocolHandler *_handler) +void Server_Player::setUserInterface(Server_AbstractUserInterface *_userInterface) { playerMutex.lock(); - handler = _handler; + userInterface = _userInterface; playerMutex.unlock(); - pingTime = _handler ? 0 : -1; + pingTime = _userInterface ? 0 : -1; Event_PlayerPropertiesChanged event; event.mutable_player_properties()->set_ping_seconds(pingTime); diff --git a/common/server_player.h b/common/server_player.h index dd831f05..b5959f1c 100644 --- a/common/server_player.h +++ b/common/server_player.h @@ -16,7 +16,7 @@ class Server_CardZone; class Server_Counter; class Server_Arrow; class Server_Card; -class Server_ProtocolHandler; +class Server_AbstractUserInterface; class ServerInfo_User; class ServerInfo_PlayerProperties; class CommandContainer; @@ -62,7 +62,7 @@ class Server_Player : public Server_ArrowTarget { private: class MoveCardCompareFunctor; Server_Game *game; - Server_ProtocolHandler *handler; + Server_AbstractUserInterface *userInterface; ServerInfo_User *userInfo; DeckList *deck; QMap zones; @@ -78,11 +78,11 @@ private: bool conceded; public: mutable QMutex playerMutex; - Server_Player(Server_Game *_game, int _playerId, const ServerInfo_User &_userInfo, bool _spectator, Server_ProtocolHandler *_handler); + Server_Player(Server_Game *_game, int _playerId, const ServerInfo_User &_userInfo, bool _spectator, Server_AbstractUserInterface *_handler); ~Server_Player(); void prepareDestroy(); - Server_ProtocolHandler *getProtocolHandler() const { return handler; } - void setProtocolHandler(Server_ProtocolHandler *_handler); + Server_AbstractUserInterface *getUserInterface() const { return userInterface; } + void setUserInterface(Server_AbstractUserInterface *_userInterface); void setPlayerId(int _id) { playerId = _id; } bool getReadyStart() const { return readyStart; } diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index aff33445..b254a868 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -36,7 +36,7 @@ #include Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, QObject *parent) - : QObject(parent), Server_AbstractUserInterface(_server), authState(NotLoggedIn), acceptsUserListChanges(false), acceptsRoomListChanges(false), sessionId(-1), timeRunning(0), lastDataReceived(0) + : QObject(parent), Server_AbstractUserInterface(_server), authState(NotLoggedIn), acceptsUserListChanges(false), acceptsRoomListChanges(false), timeRunning(0), lastDataReceived(0) { connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout())); } @@ -84,7 +84,7 @@ void Server_ProtocolHandler::prepareDestroy() if ((authState == UnknownUser) || p->getSpectator()) g->removePlayer(p); else - p->setProtocolHandler(0); + p->setUserInterface(0); g->gameMutex.unlock(); r->gamesMutex.unlock(); @@ -102,6 +102,14 @@ void Server_ProtocolHandler::playerRemovedFromGame(Server_Game *game) games.remove(game->getGameId()); } +void Server_ProtocolHandler::playerAddedToGame(int gameId, int roomId, int playerId) +{ + qDebug() << "Server_ProtocolHandler::playerAddedToGame(): gameId =" << gameId; + + QMutexLocker locker(&gameListMutex); + games.insert(gameId, QPair(roomId, playerId)); +} + void Server_ProtocolHandler::sendProtocolItem(const Response &item) { ServerMessage msg; @@ -168,7 +176,7 @@ Response::ResponseCode Server_ProtocolHandler::processSessionCommandContainer(co case SessionCommand::JOIN_ROOM: resp = cmdJoinRoom(sc.GetExtension(Command_JoinRoom::ext), rc); break; case SessionCommand::LIST_USERS: resp = cmdListUsers(sc.GetExtension(Command_ListUsers::ext), rc); break; } - if ((resp != Response::RespOk) && (resp != Response::RespNothing)) + if (resp != Response::RespOk) finalResponseCode = resp; } return finalResponseCode; @@ -196,7 +204,7 @@ Response::ResponseCode Server_ProtocolHandler::processRoomCommandContainer(const case RoomCommand::CREATE_GAME: resp = cmdCreateGame(sc.GetExtension(Command_CreateGame::ext), room, rc); break; case RoomCommand::JOIN_GAME: resp = cmdJoinGame(sc.GetExtension(Command_JoinGame::ext), room, rc); break; } - if ((resp != Response::RespOk) && (resp != Response::RespNothing)) + if (resp != Response::RespOk) finalResponseCode = resp; } return finalResponseCode; @@ -207,6 +215,8 @@ Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const if (authState == NotLoggedIn) return Response::RespLoginNeeded; + qDebug() << QString::fromStdString(cont.DebugString()); + gameListMutex.lock(); if (!games.contains(cont.game_id())) { gameListMutex.unlock(); @@ -215,27 +225,30 @@ Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const const QPair roomIdAndPlayerId = games.value(cont.game_id()); gameListMutex.unlock(); - server->roomsLock.lockForRead(); + QReadLocker roomsLocker(&server->roomsLock); Server_Room *room = server->getRooms().value(roomIdAndPlayerId.first); - if (!room) { - server->roomsLock.unlock(); + if (!room) return Response::RespNotInRoom; - } - room->gamesMutex.lock(); + + QMutexLocker roomGamesLocker(&room->gamesMutex); Server_Game *game = room->getGames().value(cont.game_id()); if (!game) { - room->gamesMutex.unlock(); - server->roomsLock.unlock(); + if (room->getExternalGames().contains(cont.game_id())) { + server->sendIsl_GameCommand(cont, + room->getExternalGames().value(cont.game_id()).server_id(), + userInfo->session_id(), + roomIdAndPlayerId.first, + roomIdAndPlayerId.second + ); + return Response::RespNothing; + } return Response::RespNotInRoom; } - game->gameMutex.lock(); + + QMutexLocker gameLocker(&game->gameMutex); Server_Player *player = game->getPlayer(roomIdAndPlayerId.second); - if (!player) { - game->gameMutex.unlock(); - room->gamesMutex.unlock(); - server->roomsLock.unlock(); + if (!player) return Response::RespNotInRoom; - } GameEventStorage ges; Response::ResponseCode finalResponseCode = Response::RespOk; @@ -245,15 +258,11 @@ Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const Response::ResponseCode resp = player->processGameCommand(sc, rc, ges); - if ((resp != Response::RespOk) && (resp != Response::RespNothing)) + if (resp != Response::RespOk) finalResponseCode = resp; } ges.sendToGame(game); - game->gameMutex.unlock(); - room->gamesMutex.unlock(); - server->roomsLock.unlock(); - return finalResponseCode; } @@ -273,7 +282,7 @@ Response::ResponseCode Server_ProtocolHandler::processModeratorCommandContainer( switch ((ModeratorCommand::ModeratorCommandType) num) { case ModeratorCommand::BAN_FROM_SERVER: resp = cmdBanFromServer(sc.GetExtension(Command_BanFromServer::ext), rc); break; } - if ((resp != Response::RespOk) && (resp != Response::RespNothing)) + if (resp != Response::RespOk) finalResponseCode = resp; } return finalResponseCode; @@ -296,7 +305,7 @@ Response::ResponseCode Server_ProtocolHandler::processAdminCommandContainer(cons case AdminCommand::SHUTDOWN_SERVER: resp = cmdShutdownServer(sc.GetExtension(Command_ShutdownServer::ext), rc); break; case AdminCommand::UPDATE_SERVER_MESSAGE: resp = cmdUpdateServerMessage(sc.GetExtension(Command_UpdateServerMessage::ext), rc); break; } - if ((resp != Response::RespOk) && (resp != Response::RespNothing)) + if (resp != Response::RespOk) finalResponseCode = resp; } return finalResponseCode; @@ -306,7 +315,7 @@ void Server_ProtocolHandler::processCommandContainer(const CommandContainer &con { lastDataReceived = timeRunning; - ResponseContainer responseContainer; + ResponseContainer responseContainer(cont.cmd_id()); Response::ResponseCode finalResponseCode; if (cont.game_command_size()) @@ -322,21 +331,8 @@ void Server_ProtocolHandler::processCommandContainer(const CommandContainer &con else finalResponseCode = Response::RespInvalidCommand; - const QList > &preResponseQueue = responseContainer.getPreResponseQueue(); - for (int i = 0; i < preResponseQueue.size(); ++i) - sendProtocolItemByType(preResponseQueue[i].first, *preResponseQueue[i].second); - - Response response; - response.set_cmd_id(cont.cmd_id()); - response.set_response_code(finalResponseCode); - ::google::protobuf::Message *responseExtension = responseContainer.getResponseExtension(); - if (responseExtension) - response.GetReflection()->MutableMessage(&response, responseExtension->GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(*responseExtension); - sendProtocolItem(response); - - const QList > &postResponseQueue = responseContainer.getPostResponseQueue(); - for (int i = 0; i < postResponseQueue.size(); ++i) - sendProtocolItemByType(postResponseQueue[i].first, *postResponseQueue[i].second); + if (finalResponseCode != Response::RespNothing) + sendResponseContainer(responseContainer, finalResponseCode); } void Server_ProtocolHandler::pingClockTimeout() @@ -411,13 +407,14 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd const QList &gamePlayers = game->getPlayers().values(); for (int j = 0; j < gamePlayers.size(); ++j) if (gamePlayers[j]->getUserInfo()->name() == userInfo->name()) { - gamePlayers[j]->setProtocolHandler(this); + gamePlayers[j]->setUserInterface(this); gameListMutex.lock(); games.insert(game->getGameId(), QPair(room->getId(), gamePlayers[j]->getPlayerId())); gameListMutex.unlock(); Event_GameJoined event1; + event1.set_room_id(room->getId()); event1.set_game_id(game->getGameId()); event1.set_game_description(game->getDescription().toStdString()); event1.set_host_id(game->getHostId()); @@ -650,41 +647,10 @@ Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_Creat if (description.size() > 60) description = description.left(60); - Server_Game *game = new Server_Game(this, server->getNextGameId(), description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes, cmd.only_buddies(), cmd.only_registered(), cmd.spectators_allowed(), cmd.spectators_need_password(), cmd.spectators_can_talk(), cmd.spectators_see_everything(), room); - game->moveToThread(room->thread()); - - game->gameMutex.lock(); + Server_Game *game = new Server_Game(copyUserInfo(false), server->getNextGameId(), description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes, cmd.only_buddies(), cmd.only_registered(), cmd.spectators_allowed(), cmd.spectators_need_password(), cmd.spectators_can_talk(), cmd.spectators_see_everything(), room); + game->addPlayer(this, rc, false, false); room->addGame(game); - Server_Player *creator = game->getPlayers().values().first(); - - gameListMutex.lock(); - games.insert(game->getGameId(), QPair(room->getId(), creator->getPlayerId())); - gameListMutex.unlock(); - - Event_GameJoined event1; - event1.set_game_id(game->getGameId()); - event1.set_game_description(game->getDescription().toStdString()); - event1.set_host_id(creator->getPlayerId()); - event1.set_player_id(creator->getPlayerId()); - event1.set_spectator(false); - event1.set_spectators_can_talk(game->getSpectatorsCanTalk()); - event1.set_spectators_see_everything(game->getSpectatorsSeeEverything()); - event1.set_resuming(false); - rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event1)); - - Event_GameStateChanged event2; - QListIterator gameStateIterator(game->getGameState(creator, false, true)); - while (gameStateIterator.hasNext()) - event2.add_player_list()->CopyFrom(gameStateIterator.next()); - event2.set_seconds_elapsed(0); - event2.set_game_started(game->getGameStarted()); - event2.set_active_player_id(game->getActivePlayer()); - event2.set_active_phase(game->getActivePhase()); - rc.enqueuePreResponseItem(ServerMessage::GAME_EVENT_CONTAINER, game->prepareGameEvent(event2, -1)); - - game->gameMutex.unlock(); - return Response::RespOk; } @@ -693,47 +659,5 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam if (authState == NotLoggedIn) return Response::RespLoginNeeded; - room->gamesMutex.lock(); - Server_Game *g = room->getGames().value(cmd.game_id()); - if (!g) { - room->gamesMutex.unlock(); - return Response::RespNameNotFound; - } - - g->gameMutex.lock(); - - Response::ResponseCode result = g->checkJoin(userInfo, QString::fromStdString(cmd.password()), cmd.spectator(), cmd.override_restrictions()); - if (result == Response::RespOk) { - Server_Player *player = g->addPlayer(this, cmd.spectator()); - - gameListMutex.lock(); - games.insert(cmd.game_id(), QPair(room->getId(), player->getPlayerId())); - gameListMutex.unlock(); - - Event_GameJoined event1; - event1.set_game_id(g->getGameId()); - event1.set_game_description(g->getDescription().toStdString()); - event1.set_host_id(g->getHostId()); - event1.set_player_id(player->getPlayerId()); - event1.set_spectator(cmd.spectator()); - event1.set_spectators_can_talk(g->getSpectatorsCanTalk()); - event1.set_spectators_see_everything(g->getSpectatorsSeeEverything()); - event1.set_resuming(false); - rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event1)); - - Event_GameStateChanged event2; - QListIterator gameStateIterator(g->getGameState(player, false, true)); - while (gameStateIterator.hasNext()) - event2.add_player_list()->CopyFrom(gameStateIterator.next()); - event2.set_seconds_elapsed(g->getSecondsElapsed()); - event2.set_game_started(g->getGameStarted()); - event2.set_active_player_id(g->getActivePlayer()); - event2.set_active_phase(g->getActivePhase()); - rc.enqueuePostResponseItem(ServerMessage::GAME_EVENT_CONTAINER, g->prepareGameEvent(event2, -1)); - } - - g->gameMutex.unlock(); - room->gamesMutex.unlock(); - - return result; + return room->processJoinGameCommand(cmd, rc, this); } diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index 91ae69de..ed3a42e4 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -63,8 +63,6 @@ protected: AuthenticationResult authState; bool acceptsUserListChanges; bool acceptsRoomListChanges; - - int sessionId; private: QMutex gameListMutex; @@ -109,19 +107,18 @@ private: private slots: void pingClockTimeout(); signals: - void logDebugMessage(const QString &message, Server_ProtocolHandler *session); + void logDebugMessage(const QString &message, void *session); public slots: void prepareDestroy(); public: Server_ProtocolHandler(Server *_server, QObject *parent = 0); ~Server_ProtocolHandler(); void playerRemovedFromGame(Server_Game *game); + void playerAddedToGame(int gameId, int roomId, int playerId); bool getAcceptsUserListChanges() const { return acceptsUserListChanges; } bool getAcceptsRoomListChanges() const { return acceptsRoomListChanges; } virtual QString getAddress() const = 0; - int getSessionId() const { return sessionId; } - void setSessionId(int _sessionId) { sessionId = _sessionId; } int getLastCommandTime() const { return timeRunning - lastDataReceived; } void processCommandContainer(const CommandContainer &cont); diff --git a/common/server_remoteuserinterface.cpp b/common/server_remoteuserinterface.cpp index b20bbbe5..cd0e3031 100644 --- a/common/server_remoteuserinterface.cpp +++ b/common/server_remoteuserinterface.cpp @@ -1,22 +1,23 @@ #include "server_remoteuserinterface.h" #include "server.h" +#include "pb/serverinfo_user.pb.h" void Server_RemoteUserInterface::sendProtocolItem(const Response &item) { - server->sendIslMessage(item, userInfo->server_id()); + server->sendIsl_Response(item, userInfo->server_id(), userInfo->session_id()); } void Server_RemoteUserInterface::sendProtocolItem(const SessionEvent &item) { - server->sendIslMessage(item, userInfo->server_id()); + server->sendIsl_SessionEvent(item, userInfo->server_id(), userInfo->session_id()); } void Server_RemoteUserInterface::sendProtocolItem(const GameEventContainer &item) { - server->sendIslMessage(item, userInfo->server_id()); + server->sendIsl_GameEventContainer(item, userInfo->server_id(), userInfo->session_id()); } void Server_RemoteUserInterface::sendProtocolItem(const RoomEvent &item) { - server->sendIslMessage(item, userInfo->server_id()); + server->sendIsl_RoomEvent(item, userInfo->server_id(), userInfo->session_id()); } diff --git a/common/server_remoteuserinterface.h b/common/server_remoteuserinterface.h index 82dafdb6..7e09d210 100644 --- a/common/server_remoteuserinterface.h +++ b/common/server_remoteuserinterface.h @@ -7,6 +7,11 @@ class Server_RemoteUserInterface : public Server_AbstractUserInterface { public: Server_RemoteUserInterface(Server *_server, const ServerInfo_User_Container &_userInfoContainer) : Server_AbstractUserInterface(_server, _userInfoContainer) { } + int getLastCommandTime() const { return 0; } + + void playerRemovedFromGame(Server_Game * /*game*/) { } + void playerAddedToGame(int /*gameId*/, int /*roomId*/, int /*playerId*/) { } + void sendProtocolItem(const Response &item); void sendProtocolItem(const SessionEvent &item); void sendProtocolItem(const GameEventContainer &item); diff --git a/common/server_response_containers.cpp b/common/server_response_containers.cpp index 11778cff..8b6d2730 100644 --- a/common/server_response_containers.cpp +++ b/common/server_response_containers.cpp @@ -63,8 +63,8 @@ void GameEventStorage::sendToGame(Server_Game *game) game->sendGameEventContainer(contOthers, GameEventStorageItem::SendToOthers, privatePlayerId); } -ResponseContainer::ResponseContainer() - : responseExtension(0) +ResponseContainer::ResponseContainer(int _cmdId) + : responseExtension(0), cmdId(_cmdId) { } diff --git a/common/server_response_containers.h b/common/server_response_containers.h index 13fab1dc..9220cdac 100644 --- a/common/server_response_containers.h +++ b/common/server_response_containers.h @@ -43,12 +43,14 @@ public: class ResponseContainer { private: + int cmdId; ::google::protobuf::Message *responseExtension; QList > preResponseQueue, postResponseQueue; public: - ResponseContainer(); + ResponseContainer(int _cmdId); ~ResponseContainer(); + int getCmdId() const { return cmdId; } void setResponseExtension(::google::protobuf::Message *_responseExtension) { responseExtension = _responseExtension; } ::google::protobuf::Message *getResponseExtension() const { return responseExtension; } void enqueuePreResponseItem(ServerMessage::MessageType type, ::google::protobuf::Message *item) { preResponseQueue.append(qMakePair(type, item)); } diff --git a/common/server_room.cpp b/common/server_room.cpp index dbb52725..3b71704f 100644 --- a/common/server_room.cpp +++ b/common/server_room.cpp @@ -3,6 +3,8 @@ #include "server_game.h" #include +#include "pb/commands.pb.h" +#include "pb/room_commands.pb.h" #include "pb/event_join_room.pb.h" #include "pb/event_leave_room.pb.h" #include "pb/event_list_games.pb.h" @@ -137,7 +139,8 @@ void Server_Room::removeExternalUser(const QString &name) { // This function is always called from the Server thread with server->roomsMutex locked. usersLock.lockForWrite(); - externalUsers.remove(name); + if (externalUsers.contains(name)) + externalUsers.remove(name); usersLock.unlock(); Event_LeaveRoom event; @@ -161,6 +164,36 @@ void Server_Room::updateExternalGameList(const ServerInfo_Game &gameInfo) emit roomInfoChanged(getInfo(false, false, true)); } +Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface) +{ + // This function is called from the Server thread and from the S_PH thread. + // server->roomsMutex is always locked. + + QMutexLocker roomGamesLocker(&gamesMutex); + Server_Game *g = games.value(cmd.game_id()); + if (!g) { + if (externalGames.contains(cmd.game_id())) { + CommandContainer cont; + cont.set_cmd_id(rc.getCmdId()); + RoomCommand *roomCommand = cont.add_room_command(); + roomCommand->GetReflection()->MutableMessage(roomCommand, cmd.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(cmd); + getServer()->sendIsl_RoomCommand(cont, externalGames.value(cmd.game_id()).server_id(), userInterface->getUserInfo()->session_id(), id); + + return Response::RespNothing; + } else + return Response::RespNameNotFound; + } + + QMutexLocker gameLocker(&g->gameMutex); + + Response::ResponseCode result = g->checkJoin(userInterface->getUserInfo(), QString::fromStdString(cmd.password()), cmd.spectator(), cmd.override_restrictions()); + if (result == Response::RespOk) + g->addPlayer(userInterface, rc, cmd.spectator()); + + return result; +} + + void Server_Room::say(const QString &userName, const QString &s, bool sendToIsl) { Event_RoomSay event; @@ -177,7 +210,7 @@ void Server_Room::sendRoomEvent(RoomEvent *event, bool sendToIsl) usersLock.unlock(); if (sendToIsl) - static_cast(parent())->sendIslMessage(*event); + static_cast(parent())->sendIsl_RoomEvent(*event); delete event; } @@ -191,11 +224,16 @@ void Server_Room::broadcastGameListUpdate(ServerInfo_Game gameInfo, bool sendToI void Server_Room::addGame(Server_Game *game) { - // Lock gamesMutex and gameMutex before calling this + // Lock gamesMutex before calling this + game->moveToThread(thread()); connect(game, SIGNAL(gameInfoChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game))); + + game->gameMutex.lock(); games.insert(game->getGameId(), game); emit gameListChanged(game->getInfo()); + game->gameMutex.unlock(); + emit roomInfoChanged(getInfo(false, false, true)); } diff --git a/common/server_room.h b/common/server_room.h index 0def72ca..0f887710 100644 --- a/common/server_room.h +++ b/common/server_room.h @@ -7,8 +7,9 @@ #include #include #include -#include "pb/serverinfo_room.pb.h" #include "serverinfo_user_container.h" +#include "pb/serverinfo_room.pb.h" +#include "pb/response.pb.h" class Server_ProtocolHandler; class RoomEvent; @@ -18,6 +19,10 @@ class ServerInfo_Game; class Server_Game; class Server; +class Command_JoinGame; +class ResponseContainer; +class Server_AbstractUserInterface; + class Server_Room : public QObject { Q_OBJECT signals: @@ -48,6 +53,7 @@ public: QString getJoinMessage() const { return joinMessage; } const QStringList &getGameTypes() const { return gameTypes; } const QMap &getGames() const { return games; } + const QMap &getExternalGames() const { return externalGames; } Server *getServer() const; ServerInfo_Room getInfo(bool complete, bool showGameTypes = false, bool updating = false, bool includeExternalData = true) const; int getGamesCreatedByUser(const QString &name) const; @@ -61,6 +67,8 @@ public: const QMap &getExternalUsers() const { return externalUsers; } void updateExternalGameList(const ServerInfo_Game &gameInfo); + Response::ResponseCode processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface); + void say(const QString &userName, const QString &s, bool sendToIsl = true); void addGame(Server_Game *game); diff --git a/common/serverinfo_user_container.cpp b/common/serverinfo_user_container.cpp index 6268f15a..8e50568c 100644 --- a/common/serverinfo_user_container.cpp +++ b/common/serverinfo_user_container.cpp @@ -36,6 +36,7 @@ ServerInfo_User ServerInfo_User_Container::copyUserInfo(bool complete, bool mode if (userInfo) { result.CopyFrom(*userInfo); if (!moderatorInfo) { + result.clear_session_id(); result.clear_address(); result.clear_id(); } diff --git a/servatrice/src/isl_interface.cpp b/servatrice/src/isl_interface.cpp index f4e03f6e..771c49ae 100644 --- a/servatrice/src/isl_interface.cpp +++ b/servatrice/src/isl_interface.cpp @@ -7,6 +7,7 @@ #include "get_pb_extension.h" #include "pb/isl_message.pb.h" +#include "pb/event_game_joined.pb.h" #include "pb/event_server_complete_list.pb.h" #include "pb/event_user_message.pb.h" #include "pb/event_user_joined.pb.h" @@ -280,15 +281,6 @@ void IslInterface::sessionEvent_ServerCompleteList(const Event_ServerCompleteLis } } -void IslInterface::sessionEvent_UserMessage(const SessionEvent &sessionEvent, const Event_UserMessage &event) -{ - QReadLocker locker(&server->clientsLock); - - Server_ProtocolHandler *userInterface = server->getUsers().value(QString::fromStdString(event.receiver_name())); - if (userInterface) - userInterface->sendProtocolItem(sessionEvent); -} - void IslInterface::sessionEvent_UserJoined(const Event_UserJoined &event) { ServerInfo_User userInfo(event.user_info()); @@ -327,13 +319,41 @@ void IslInterface::roomEvent_ListGames(int roomId, const Event_ListGames &event) } } -void IslInterface::processSessionEvent(const SessionEvent &event) +void IslInterface::roomCommand_JoinGame(const Command_JoinGame &cmd, int cmdId, int roomId, qint64 sessionId) +{ + emit joinGameCommandReceived(cmd, cmdId, roomId, serverId, sessionId); +} + +void IslInterface::processSessionEvent(const SessionEvent &event, qint64 sessionId) { switch (getPbExtension(event)) { case SessionEvent::SERVER_COMPLETE_LIST: sessionEvent_ServerCompleteList(event.GetExtension(Event_ServerCompleteList::ext)); break; - case SessionEvent::USER_MESSAGE: sessionEvent_UserMessage(event, event.GetExtension(Event_UserMessage::ext)); break; case SessionEvent::USER_JOINED: sessionEvent_UserJoined(event.GetExtension(Event_UserJoined::ext)); break; case SessionEvent::USER_LEFT: sessionEvent_UserLeft(event.GetExtension(Event_UserLeft::ext)); break; + case SessionEvent::GAME_JOINED: { + QReadLocker clientsLocker(&server->clientsLock); + Server_AbstractUserInterface *client = server->getUsersBySessionId().value(sessionId); + if (!client) { + qDebug() << "IslInterface::processSessionEvent: session id" << sessionId << "not found"; + break; + } + const Event_GameJoined &gameJoined = event.GetExtension(Event_GameJoined::ext); + client->playerAddedToGame(gameJoined.game_id(), gameJoined.room_id(), gameJoined.player_id()); + client->sendProtocolItem(event); + break; + } + case SessionEvent::USER_MESSAGE: + case SessionEvent::REPLAY_ADDED: { + QReadLocker clientsLocker(&server->clientsLock); + Server_AbstractUserInterface *client = server->getUsersBySessionId().value(sessionId); + if (!client) { + qDebug() << "IslInterface::processSessionEvent: session id" << sessionId << "not found"; + break; + } + + client->sendProtocolItem(event); + break; + } default: ; } } @@ -349,19 +369,40 @@ void IslInterface::processRoomEvent(const RoomEvent &event) } } +void IslInterface::processRoomCommand(const CommandContainer &cont, qint64 sessionId) +{ + for (int i = 0; i < cont.room_command_size(); ++i) { + const RoomCommand &roomCommand = cont.room_command(i); + switch (static_cast(getPbExtension(roomCommand))) { + case RoomCommand::JOIN_GAME: roomCommand_JoinGame(roomCommand.GetExtension(Command_JoinGame::ext), cont.cmd_id(), cont.room_id(), sessionId); + default: ; + } + } +} + void IslInterface::processMessage(const IslMessage &item) { qDebug() << QString::fromStdString(item.DebugString()); switch (item.message_type()) { - case IslMessage::SESSION_EVENT: processSessionEvent(item.session_event()); break; - case IslMessage::RESPONSE: { + case IslMessage::ROOM_COMMAND_CONTAINER: { + processRoomCommand(item.room_command(), item.session_id()); break; } case IslMessage::GAME_COMMAND_CONTAINER: { + emit gameCommandContainerReceived(item.game_command(), item.player_id(), serverId, item.session_id()); + break; + } + case IslMessage::SESSION_EVENT: { + processSessionEvent(item.session_event(), item.session_id()); + break; + } + case IslMessage::RESPONSE: { + emit responseReceived(item.response(), item.session_id()); break; } case IslMessage::GAME_EVENT_CONTAINER: { + emit gameEventContainerReceived(item.game_event_container(), item.session_id()); break; } case IslMessage::ROOM_EVENT: { diff --git a/servatrice/src/isl_interface.h b/servatrice/src/isl_interface.h index 6469f596..cd1787ff 100644 --- a/servatrice/src/isl_interface.h +++ b/servatrice/src/isl_interface.h @@ -21,6 +21,7 @@ class Event_JoinRoom; class Event_LeaveRoom; class Event_RoomSay; class Event_ListGames; +class Command_JoinGame; class IslInterface : public QObject { Q_OBJECT @@ -37,6 +38,10 @@ signals: void externalRoomUserLeft(int roomId, QString userName); void externalRoomSay(int roomId, QString userName, QString message); void externalRoomGameListChanged(int roomId, ServerInfo_Game gameInfo); + void joinGameCommandReceived(const Command_JoinGame &cmd, int cmdId, int roomId, int serverId, qint64 sessionId); + void gameCommandContainerReceived(const CommandContainer &cont, int playerId, int serverId, qint64 sessionId); + void responseReceived(const Response &resp, qint64 sessionId); + void gameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId); private: int serverId; int socketDescriptor; @@ -53,7 +58,6 @@ private: int messageLength; void sessionEvent_ServerCompleteList(const Event_ServerCompleteList &event); - void sessionEvent_UserMessage(const SessionEvent &sessionEvent, const Event_UserMessage &event); void sessionEvent_UserJoined(const Event_UserJoined &event); void sessionEvent_UserLeft(const Event_UserLeft &event); @@ -62,8 +66,11 @@ private: void roomEvent_Say(int roomId, const Event_RoomSay &event); void roomEvent_ListGames(int roomId, const Event_ListGames &event); - void processSessionEvent(const SessionEvent &event); + void roomCommand_JoinGame(const Command_JoinGame &cmd, int cmdId, int roomId, qint64 sessionId); + + void processSessionEvent(const SessionEvent &event, qint64 sessionId); void processRoomEvent(const RoomEvent &event); + void processRoomCommand(const CommandContainer &cont, qint64 sessionId); void processMessage(const IslMessage &item); void sharedCtor(const QSslCertificate &cert, const QSslKey &privateKey); diff --git a/servatrice/src/main.cpp b/servatrice/src/main.cpp index ae253c8f..6a54e129 100644 --- a/servatrice/src/main.cpp +++ b/servatrice/src/main.cpp @@ -118,6 +118,7 @@ int main(int argc, char *argv[]) QStringList args = app.arguments(); bool testRandom = args.contains("--test-random"); bool testHashFunction = args.contains("--test-hash"); + bool logToConsole = args.contains("--log-to-console"); qRegisterMetaType >("QList"); @@ -126,13 +127,16 @@ int main(int argc, char *argv[]) QSettings *settings = new QSettings("servatrice.ini", QSettings::IniFormat); loggerThread = new QThread; - logger = new ServerLogger; + logger = new ServerLogger(logToConsole); logger->moveToThread(loggerThread); loggerThread->start(); QMetaObject::invokeMethod(logger, "startLog", Qt::BlockingQueuedConnection, Q_ARG(QString, settings->value("server/logfile").toString())); - qInstallMsgHandler(myMessageOutput2); + if (logToConsole) + qInstallMsgHandler(myMessageOutput); + else + qInstallMsgHandler(myMessageOutput2); #ifdef Q_OS_UNIX struct sigaction hup; hup.sa_handler = ServerLogger::hupSignalHandler; @@ -159,6 +163,7 @@ int main(int argc, char *argv[]) testHash(); Servatrice *server = new Servatrice(settings); + QObject::connect(server, SIGNAL(logDebugMessage(QString, void *)), logger, SLOT(logMessage(QString, void *))); QObject::connect(server, SIGNAL(destroyed()), &app, SLOT(quit()), Qt::QueuedConnection); std::cerr << "-------------------------" << std::endl; diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index b677c977..e49f4c88 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -65,8 +65,6 @@ void Servatrice_IslServer::incomingConnection(int socketDescriptor) Servatrice::Servatrice(QSettings *_settings, QObject *parent) : Server(parent), dbMutex(QMutex::Recursive), settings(_settings), uptime(0), shutdownTimer(0) { - qRegisterMetaType("ServerInfo_User"); - serverName = settings->value("server/name").toString(); serverId = settings->value("server/id", 0).toInt(); @@ -558,7 +556,7 @@ bool Servatrice::userSessionExists(const QString &userName) return query.next(); } -int Servatrice::startSession(const QString &userName, const QString &address) +qint64 Servatrice::startSession(const QString &userName, const QString &address) { if (authenticationMethod == AuthenticationNone) return -1; @@ -577,7 +575,7 @@ int Servatrice::startSession(const QString &userName, const QString &address) return -1; } -void Servatrice::endSession(int sessionId) +void Servatrice::endSession(qint64 sessionId) { if (authenticationMethod == AuthenticationNone) return; @@ -780,7 +778,10 @@ void Servatrice::storeGameInformation(int secondsElapsed, const QSet &a allUsersIterator.toFront(); clientsLock.lockForRead(); while (allUsersIterator.hasNext()) { - Server_ProtocolHandler *userHandler = users.value(allUsersIterator.next()); + const QString userName = allUsersIterator.next(); + Server_AbstractUserInterface *userHandler = users.value(userName); + if (!userHandler) + userHandler = externalUsers.value(userName); if (userHandler) userHandler->sendProtocolItem(*sessionEvent); } @@ -916,6 +917,10 @@ void Servatrice::addIslInterface(int serverId, IslInterface *interface) connect(interface, SIGNAL(externalRoomUserLeft(int, QString)), this, SLOT(externalRoomUserLeft(int, QString))); connect(interface, SIGNAL(externalRoomSay(int, QString, QString)), this, SLOT(externalRoomSay(int, QString, QString))); connect(interface, SIGNAL(externalRoomGameListChanged(int, ServerInfo_Game)), this, SLOT(externalRoomGameListChanged(int, ServerInfo_Game))); + connect(interface, SIGNAL(joinGameCommandReceived(Command_JoinGame, int, int, int, qint64)), this, SLOT(externalJoinGameCommandReceived(Command_JoinGame, int, int, int, qint64))); + connect(interface, SIGNAL(gameCommandContainerReceived(CommandContainer, int, int, qint64)), this, SLOT(externalGameCommandContainerReceived(CommandContainer, int, int, qint64))); + connect(interface, SIGNAL(responseReceived(Response, qint64)), this, SLOT(externalResponseReceived(Response, qint64))); + connect(interface, SIGNAL(gameEventContainerReceived(GameEventContainer, qint64)), this, SLOT(externalGameEventContainerReceived(GameEventContainer, qint64))); } void Servatrice::removeIslInterface(int serverId) diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 52aa6650..4411c3dc 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -127,8 +127,8 @@ public: QList getServerList() const; protected: - int startSession(const QString &userName, const QString &address); - void endSession(int sessionId); + qint64 startSession(const QString &userName, const QString &address); + void endSession(qint64 sessionId); bool userExists(const QString &user); AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr); diff --git a/servatrice/src/server_logger.cpp b/servatrice/src/server_logger.cpp index fe3aa9db..ca3e1a70 100644 --- a/servatrice/src/server_logger.cpp +++ b/servatrice/src/server_logger.cpp @@ -3,13 +3,14 @@ #include #include #include +#include #ifdef Q_OS_UNIX # include # include #endif -ServerLogger::ServerLogger(QObject *parent) - : QObject(parent), flushRunning(false) +ServerLogger::ServerLogger(bool _logToConsole, QObject *parent) + : QObject(parent), logToConsole(_logToConsole), flushRunning(false) { } @@ -71,6 +72,9 @@ void ServerLogger::flushBuffer() stream << message << "\n"; stream.flush(); + + if (logToConsole) + std::cout << message.toStdString() << std::endl; } } diff --git a/servatrice/src/server_logger.h b/servatrice/src/server_logger.h index 8a17936b..67b293cf 100644 --- a/servatrice/src/server_logger.h +++ b/servatrice/src/server_logger.h @@ -14,7 +14,7 @@ class Server_ProtocolHandler; class ServerLogger : public QObject { Q_OBJECT public: - ServerLogger(QObject *parent = 0); + ServerLogger(bool _logToConsole, QObject *parent = 0); ~ServerLogger(); static void hupSignalHandler(int unused); public slots: @@ -26,6 +26,7 @@ private slots: signals: void sigFlushBuffer(); private: + bool logToConsole; static int sigHupFD[2]; QSocketNotifier *snHup; static QFile *logFile;