#include #include "rng_abstract.h" #include "server_protocolhandler.h" #include "server_room.h" #include "server_card.h" #include "server_arrow.h" #include "server_cardzone.h" #include "server_counter.h" #include "server_game.h" #include "server_player.h" #include "decklist.h" #include #include "pb/serverinfo_zone.pb.h" #include "pb/commands.pb.h" #include "pb/command_attach_card.pb.h" #include "pb/command_concede.pb.h" #include "pb/command_create_arrow.pb.h" #include "pb/command_create_counter.pb.h" #include "pb/command_create_token.pb.h" #include "pb/command_deck_select.pb.h" #include "pb/command_del_counter.pb.h" #include "pb/command_delete_arrow.pb.h" #include "pb/command_draw_cards.pb.h" #include "pb/command_dump_zone.pb.h" #include "pb/command_flip_card.pb.h" #include "pb/command_game_say.pb.h" #include "pb/command_inc_card_counter.pb.h" #include "pb/command_inc_counter.pb.h" #include "pb/command_kick_from_game.pb.h" #include "pb/command_leave_game.pb.h" #include "pb/command_move_card.pb.h" #include "pb/command_mulligan.pb.h" #include "pb/command_next_turn.pb.h" #include "pb/command_ready_start.pb.h" #include "pb/command_reveal_cards.pb.h" #include "pb/command_roll_die.pb.h" #include "pb/command_set_active_phase.pb.h" #include "pb/command_set_card_attr.pb.h" #include "pb/command_set_card_counter.pb.h" #include "pb/command_set_counter.pb.h" #include "pb/command_set_sideboard_plan.pb.h" #include "pb/command_shuffle.pb.h" #include "pb/command_stop_dump_zone.pb.h" #include "pb/command_undo_draw.pb.h" #include "pb/command_deck_upload.pb.h" #include "pb/command_deck_download.pb.h" #include "pb/command_deck_new_dir.pb.h" #include "pb/command_deck_del_dir.pb.h" #include "pb/command_deck_del.pb.h" #include "pb/response.pb.h" #include "pb/response_login.pb.h" #include "pb/response_list_users.pb.h" #include "pb/response_get_games_of_user.pb.h" #include "pb/response_get_user_info.pb.h" #include "pb/response_join_room.pb.h" #include "pb/response_deck_download.pb.h" #include "pb/response_dump_zone.pb.h" #include "pb/event_list_rooms.pb.h" #include "pb/event_server_message.pb.h" #include "pb/event_user_message.pb.h" #include "pb/event_game_say.pb.h" #include "pb/event_game_joined.pb.h" #include "pb/event_game_state_changed.pb.h" #include "pb/event_shuffle.pb.h" #include "pb/event_roll_die.pb.h" #include "pb/event_player_properties_changed.pb.h" #include "pb/event_create_arrow.pb.h" #include "pb/event_delete_arrow.pb.h" #include "pb/event_set_card_counter.pb.h" #include "pb/event_flip_card.pb.h" #include "pb/event_attach_card.pb.h" #include "pb/event_create_token.pb.h" #include "pb/event_room_say.pb.h" #include "pb/event_create_counter.pb.h" #include "pb/event_del_counter.pb.h" #include "pb/event_set_counter.pb.h" #include "pb/event_dump_zone.pb.h" #include "pb/event_stop_dump_zone.pb.h" #include "pb/event_reveal_cards.pb.h" #include "pb/context_deck_select.pb.h" #include "pb/context_concede.pb.h" #include "pb/context_ready_start.pb.h" #include "pb/context_mulligan.pb.h" #include Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, QObject *parent) : QObject(parent), server(_server), authState(NotLoggedIn), acceptsUserListChanges(false), acceptsRoomListChanges(false), userInfo(0), sessionId(-1), timeRunning(0), lastDataReceived(0), gameListMutex(QMutex::Recursive) { connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout())); } Server_ProtocolHandler::~Server_ProtocolHandler() { } // This is essentially the destructor, but it needs to be called from the // child's destructor so that the server mutex does not get unlocked during // finalization. void Server_ProtocolHandler::prepareDestroy() { QMutexLocker locker(&server->serverMutex); qDebug("Server_ProtocolHandler::prepareDestroy"); server->removeClient(this); QMapIterator roomIterator(rooms); while (roomIterator.hasNext()) roomIterator.next().value()->removeClient(this); gameListMutex.lock(); QMapIterator > gameIterator(games); while (gameIterator.hasNext()) { gameIterator.next(); Server_Game *g = gameIterator.value().first; Server_Player *p = gameIterator.value().second; if ((authState == UnknownUser) || p->getSpectator()) g->removePlayer(p); else { p->setProtocolHandler(0); g->postConnectionStatusUpdate(p, false); } } gameListMutex.unlock(); delete userInfo; } void Server_ProtocolHandler::setUserInfo(const ServerInfo_User &_userInfo) { userInfo = new ServerInfo_User; userInfo->CopyFrom(_userInfo); } ServerInfo_User Server_ProtocolHandler::copyUserInfo(bool complete, bool moderatorInfo) const { ServerInfo_User result; if (userInfo) { result.CopyFrom(*userInfo); if (!moderatorInfo) result.clear_address(); if (!complete) result.clear_avatar_bmp(); } return result; } void Server_ProtocolHandler::playerRemovedFromGame(Server_Game *game) { qDebug() << "Server_ProtocolHandler::playerRemovedFromGame(): gameId =" << game->getGameId(); QMutexLocker locker(&gameListMutex); games.remove(game->getGameId()); } void Server_ProtocolHandler::sendProtocolItem(const Response &item) { ServerMessage msg; msg.mutable_response()->CopyFrom(item); msg.set_message_type(ServerMessage::RESPONSE); transmitProtocolItem(msg); } void Server_ProtocolHandler::sendProtocolItem(const SessionEvent &item) { ServerMessage msg; msg.mutable_session_event()->CopyFrom(item); msg.set_message_type(ServerMessage::SESSION_EVENT); transmitProtocolItem(msg); } void Server_ProtocolHandler::sendProtocolItem(const GameEventContainer &item) { ServerMessage msg; msg.mutable_game_event_container()->CopyFrom(item); msg.set_message_type(ServerMessage::GAME_EVENT_CONTAINER); transmitProtocolItem(msg); } void Server_ProtocolHandler::sendProtocolItem(const RoomEvent &item) { ServerMessage msg; msg.mutable_room_event()->CopyFrom(item); msg.set_message_type(ServerMessage::ROOM_EVENT); transmitProtocolItem(msg); } void Server_ProtocolHandler::sendProtocolItem(ServerMessage::MessageType type, const ::google::protobuf::Message &item) { switch (type) { case ServerMessage::RESPONSE: sendProtocolItem(static_cast(item)); break; case ServerMessage::SESSION_EVENT: sendProtocolItem(static_cast(item)); break; case ServerMessage::GAME_EVENT_CONTAINER: sendProtocolItem(static_cast(item)); break; case ServerMessage::ROOM_EVENT: sendProtocolItem(static_cast(item)); break; } } SessionEvent *Server_ProtocolHandler::prepareSessionEvent(const ::google::protobuf::Message &sessionEvent) { SessionEvent *event = new SessionEvent; event->GetReflection()->MutableMessage(event, sessionEvent.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(sessionEvent); return event; } Response::ResponseCode Server_ProtocolHandler::processSessionCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { Response::ResponseCode finalResponseCode = Response::RespOk; for (int i = cont.session_command_size() - 1; i >= 0; --i) { Response::ResponseCode resp = Response::RespInvalidCommand; const SessionCommand &sc = cont.session_command(i); std::vector< const ::google::protobuf::FieldDescriptor * > fieldList; sc.GetReflection()->ListFields(sc, &fieldList); int num = 0; for (unsigned int j = 0; j < fieldList.size(); ++j) if (fieldList[j]->is_extension()) { num = fieldList[j]->number(); break; } switch ((SessionCommand::SessionCommandType) num) { case SessionCommand::PING: resp = cmdPing(sc.GetExtension(Command_Ping::ext), rc); break; case SessionCommand::LOGIN: resp = cmdLogin(sc.GetExtension(Command_Login::ext), rc); break; case SessionCommand::MESSAGE: resp = cmdMessage(sc.GetExtension(Command_Message::ext), rc); break; case SessionCommand::ADD_TO_LIST: resp = cmdAddToList(sc.GetExtension(Command_AddToList::ext), rc); break; case SessionCommand::REMOVE_FROM_LIST: resp = cmdRemoveFromList(sc.GetExtension(Command_RemoveFromList::ext), rc); break; case SessionCommand::DECK_LIST: resp = cmdDeckList(sc.GetExtension(Command_DeckList::ext), rc); break; case SessionCommand::DECK_NEW_DIR: resp = cmdDeckNewDir(sc.GetExtension(Command_DeckNewDir::ext), rc); break; case SessionCommand::DECK_DEL_DIR: resp = cmdDeckDelDir(sc.GetExtension(Command_DeckDelDir::ext), rc); break; case SessionCommand::DECK_DEL: resp = cmdDeckDel(sc.GetExtension(Command_DeckDel::ext), rc); break; case SessionCommand::DECK_UPLOAD: resp = cmdDeckUpload(sc.GetExtension(Command_DeckUpload::ext), rc); break; case SessionCommand::DECK_DOWNLOAD: resp = cmdDeckDownload(sc.GetExtension(Command_DeckDownload::ext), rc); break; case SessionCommand::GET_GAMES_OF_USER: resp = cmdGetGamesOfUser(sc.GetExtension(Command_GetGamesOfUser::ext), rc); break; case SessionCommand::GET_USER_INFO: resp = cmdGetUserInfo(sc.GetExtension(Command_GetUserInfo::ext), rc); break; case SessionCommand::LIST_ROOMS: resp = cmdListRooms(sc.GetExtension(Command_ListRooms::ext), rc); break; 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)) finalResponseCode = resp; } return finalResponseCode; } Response::ResponseCode Server_ProtocolHandler::processRoomCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; Server_Room *room = rooms.value(cont.room_id(), 0); if (!room) return Response::RespNotInRoom; QMutexLocker locker(&room->roomMutex); Response::ResponseCode finalResponseCode = Response::RespOk; for (int i = cont.room_command_size() - 1; i >= 0; --i) { Response::ResponseCode resp = Response::RespInvalidCommand; const RoomCommand &sc = cont.room_command(i); std::vector< const ::google::protobuf::FieldDescriptor * > fieldList; sc.GetReflection()->ListFields(sc, &fieldList); int num = 0; for (unsigned int j = 0; j < fieldList.size(); ++j) if (fieldList[j]->is_extension()) { num = fieldList[j]->number(); break; } switch ((RoomCommand::RoomCommandType) num) { case RoomCommand::LEAVE_ROOM: resp = cmdLeaveRoom(sc.GetExtension(Command_LeaveRoom::ext), room, rc); break; case RoomCommand::ROOM_SAY: resp = cmdRoomSay(sc.GetExtension(Command_RoomSay::ext), room, rc); break; 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)) finalResponseCode = resp; } return finalResponseCode; } Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; gameListMutex.lock(); if (!games.contains(cont.game_id())) { qDebug() << "invalid game"; return Response::RespNotInRoom; } QPair gamePair = games.value(cont.game_id()); Server_Game *game = gamePair.first; Server_Player *player = gamePair.second; QMutexLocker locker(&game->gameMutex); gameListMutex.unlock(); GameEventStorage ges; Response::ResponseCode finalResponseCode = Response::RespOk; for (int i = cont.game_command_size() - 1; i >= 0; --i) { Response::ResponseCode resp = Response::RespInvalidCommand; const GameCommand &sc = cont.game_command(i); std::vector< const ::google::protobuf::FieldDescriptor * > fieldList; sc.GetReflection()->ListFields(sc, &fieldList); int num = 0; for (unsigned int j = 0; j < fieldList.size(); ++j) if (fieldList[j]->is_extension()) { num = fieldList[j]->number(); break; } switch ((GameCommand::GameCommandType) num) { case GameCommand::KICK_FROM_GAME: resp = cmdKickFromGame(sc.GetExtension(Command_KickFromGame::ext), game, player, rc, ges); break; case GameCommand::LEAVE_GAME: resp = cmdLeaveGame(sc.GetExtension(Command_LeaveGame::ext), game, player, rc, ges); break; case GameCommand::GAME_SAY: resp = cmdGameSay(sc.GetExtension(Command_GameSay::ext), game, player, rc, ges); break; case GameCommand::SHUFFLE: resp = cmdShuffle(sc.GetExtension(Command_Shuffle::ext), game, player, rc, ges); break; case GameCommand::MULLIGAN: resp = cmdMulligan(sc.GetExtension(Command_Mulligan::ext), game, player, rc, ges); break; case GameCommand::ROLL_DIE: resp = cmdRollDie(sc.GetExtension(Command_RollDie::ext), game, player, rc, ges); break; case GameCommand::DRAW_CARDS: resp = cmdDrawCards(sc.GetExtension(Command_DrawCards::ext), game, player, rc, ges); break; case GameCommand::UNDO_DRAW: resp = cmdUndoDraw(sc.GetExtension(Command_UndoDraw::ext), game, player, rc, ges); break; case GameCommand::FLIP_CARD: resp = cmdFlipCard(sc.GetExtension(Command_FlipCard::ext), game, player, rc, ges); break; case GameCommand::ATTACH_CARD: resp = cmdAttachCard(sc.GetExtension(Command_AttachCard::ext), game, player, rc, ges); break; case GameCommand::CREATE_TOKEN: resp = cmdCreateToken(sc.GetExtension(Command_CreateToken::ext), game, player, rc, ges); break; case GameCommand::CREATE_ARROW: resp = cmdCreateArrow(sc.GetExtension(Command_CreateArrow::ext), game, player, rc, ges); break; case GameCommand::DELETE_ARROW: resp = cmdDeleteArrow(sc.GetExtension(Command_DeleteArrow::ext), game, player, rc, ges); break; case GameCommand::SET_CARD_ATTR: resp = cmdSetCardAttr(sc.GetExtension(Command_SetCardAttr::ext), game, player, rc, ges); break; case GameCommand::SET_CARD_COUNTER: resp = cmdSetCardCounter(sc.GetExtension(Command_SetCardCounter::ext), game, player, rc, ges); break; case GameCommand::INC_CARD_COUNTER: resp = cmdIncCardCounter(sc.GetExtension(Command_IncCardCounter::ext), game, player, rc, ges); break; case GameCommand::READY_START: resp = cmdReadyStart(sc.GetExtension(Command_ReadyStart::ext), game, player, rc, ges); break; case GameCommand::CONCEDE: resp = cmdConcede(sc.GetExtension(Command_Concede::ext), game, player, rc, ges); break; case GameCommand::INC_COUNTER: resp = cmdIncCounter(sc.GetExtension(Command_IncCounter::ext), game, player, rc, ges); break; case GameCommand::CREATE_COUNTER: resp = cmdCreateCounter(sc.GetExtension(Command_CreateCounter::ext), game, player, rc, ges); break; case GameCommand::SET_COUNTER: resp = cmdSetCounter(sc.GetExtension(Command_SetCounter::ext), game, player, rc, ges); break; case GameCommand::DEL_COUNTER: resp = cmdDelCounter(sc.GetExtension(Command_DelCounter::ext), game, player, rc, ges); break; case GameCommand::NEXT_TURN: resp = cmdNextTurn(sc.GetExtension(Command_NextTurn::ext), game, player, rc, ges); break; case GameCommand::SET_ACTIVE_PHASE: resp = cmdSetActivePhase(sc.GetExtension(Command_SetActivePhase::ext), game, player, rc, ges); break; case GameCommand::DUMP_ZONE: resp = cmdDumpZone(sc.GetExtension(Command_DumpZone::ext), game, player, rc, ges); break; case GameCommand::STOP_DUMP_ZONE: resp = cmdStopDumpZone(sc.GetExtension(Command_StopDumpZone::ext), game, player, rc, ges); break; case GameCommand::REVEAL_CARDS: resp = cmdRevealCards(sc.GetExtension(Command_RevealCards::ext), game, player, rc, ges); break; case GameCommand::MOVE_CARD: resp = cmdMoveCard(sc.GetExtension(Command_MoveCard::ext), game, player, rc, ges); break; case GameCommand::SET_SIDEBOARD_PLAN: resp = cmdSetSideboardPlan(sc.GetExtension(Command_SetSideboardPlan::ext), game, player, rc, ges); break; case GameCommand::DECK_SELECT: resp = cmdDeckSelect(sc.GetExtension(Command_DeckSelect::ext), game, player, rc, ges); break; } if ((resp != Response::RespOk) && (resp != Response::RespNothing)) finalResponseCode = resp; } GameEventContainer *contPrivate = new GameEventContainer; GameEventContainer *contOthers = new GameEventContainer; const QList &gameEventList = ges.getGameEventList(); for (int i = 0; i < gameEventList.size(); ++i) { const GameEvent &event = gameEventList[i]->getGameEvent(); const GameEventStorageItem::EventRecipients recipients = gameEventList[i]->getRecipients(); if (recipients.testFlag(GameEventStorageItem::SendToPrivate)) contPrivate->add_event_list()->CopyFrom(event); if (recipients.testFlag(GameEventStorageItem::SendToOthers)) contOthers->add_event_list()->CopyFrom(event); } if (ges.getGameEventContext()) { contPrivate->mutable_context()->CopyFrom(*ges.getGameEventContext()); contOthers->mutable_context()->CopyFrom(*ges.getGameEventContext()); } game->sendGameEventContainer(contPrivate, GameEventStorageItem::SendToPrivate, ges.getPrivatePlayerId()); game->sendGameEventContainer(contOthers, GameEventStorageItem::SendToOthers, ges.getPrivatePlayerId()); return finalResponseCode; } Response::ResponseCode Server_ProtocolHandler::processModeratorCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { if (!userInfo) return Response::RespLoginNeeded; if (!(userInfo->user_level() & ServerInfo_User::IsModerator)) return Response::RespLoginNeeded; Response::ResponseCode finalResponseCode = Response::RespOk; for (int i = cont.moderator_command_size() - 1; i >= 0; --i) { Response::ResponseCode resp = Response::RespInvalidCommand; const ModeratorCommand &sc = cont.moderator_command(i); std::vector< const ::google::protobuf::FieldDescriptor * > fieldList; sc.GetReflection()->ListFields(sc, &fieldList); int num = 0; for (unsigned int j = 0; j < fieldList.size(); ++j) if (fieldList[j]->is_extension()) { num = fieldList[j]->number(); break; } 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)) finalResponseCode = resp; } return finalResponseCode; } Response::ResponseCode Server_ProtocolHandler::processAdminCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { if (!userInfo) return Response::RespLoginNeeded; if (!(userInfo->user_level() & ServerInfo_User::IsAdmin)) return Response::RespLoginNeeded; Response::ResponseCode finalResponseCode = Response::RespOk; for (int i = cont.admin_command_size() - 1; i >= 0; --i) { Response::ResponseCode resp = Response::RespInvalidCommand; const AdminCommand &sc = cont.admin_command(i); std::vector< const ::google::protobuf::FieldDescriptor * > fieldList; sc.GetReflection()->ListFields(sc, &fieldList); int num = 0; for (unsigned int j = 0; j < fieldList.size(); ++j) if (fieldList[j]->is_extension()) { num = fieldList[j]->number(); break; } switch ((AdminCommand::AdminCommandType) num) { 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)) finalResponseCode = resp; } return finalResponseCode; } void Server_ProtocolHandler::processCommandContainer(const CommandContainer &cont) { lastDataReceived = timeRunning; ResponseContainer responseContainer; Response::ResponseCode finalResponseCode; if (cont.game_command_size()) finalResponseCode = processGameCommandContainer(cont, responseContainer); else if (cont.room_command_size()) finalResponseCode = processRoomCommandContainer(cont, responseContainer); else if (cont.session_command_size()) finalResponseCode = processSessionCommandContainer(cont, responseContainer); else if (cont.moderator_command_size()) finalResponseCode = processModeratorCommandContainer(cont, responseContainer); else if (cont.admin_command_size()) finalResponseCode = processAdminCommandContainer(cont, responseContainer); else finalResponseCode = Response::RespInvalidCommand; const QList > &preResponseQueue = responseContainer.getPreResponseQueue(); for (int i = 0; i < preResponseQueue.size(); ++i) sendProtocolItem(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) sendProtocolItem(postResponseQueue[i].first, *postResponseQueue[i].second); } void Server_ProtocolHandler::pingClockTimeout() { int interval = server->getMessageCountingInterval(); if (interval > 0) { messageSizeOverTime.prepend(0); if (messageSizeOverTime.size() > server->getMessageCountingInterval()) messageSizeOverTime.removeLast(); messageCountOverTime.prepend(0); if (messageCountOverTime.size() > server->getMessageCountingInterval()) messageCountOverTime.removeLast(); } if (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime()) deleteLater(); ++timeRunning; } QPair Server_ProtocolHandler::getGame(int gameId) const { if (games.contains(gameId)) return games.value(gameId); return QPair(0, 0); } Response::ResponseCode Server_ProtocolHandler::cmdPing(const Command_Ping & /*cmd*/, ResponseContainer & /*rc*/) { return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd, ResponseContainer &rc) { QString userName = QString::fromStdString(cmd.user_name()).simplified(); if (userName.isEmpty() || (userInfo != 0)) return Response::RespContextError; QString reasonStr; AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr); switch (res) { case UserIsBanned: { Response_Login *re = new Response_Login; re->set_denied_reason_str(reasonStr.toStdString()); rc.setResponseExtension(re); return Response::RespUserIsBanned; } case NotLoggedIn: return Response::RespWrongPassword; case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession; default: authState = res; } userName = QString::fromStdString(userInfo->name()); Event_ServerMessage event; event.set_message(server->getLoginMessage().toStdString()); rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event)); Response_Login *re = new Response_Login; re->mutable_user_info()->CopyFrom(copyUserInfo(true)); if (authState == PasswordRight) { QMapIterator buddyIterator(server->getBuddyList(userName)); while (buddyIterator.hasNext()) re->add_buddy_list()->CopyFrom(buddyIterator.next().value()); QMapIterator ignoreIterator(server->getIgnoreList(userName)); while (ignoreIterator.hasNext()) re->add_ignore_list()->CopyFrom(ignoreIterator.next().value()); } server->serverMutex.lock(); QMapIterator roomIterator(server->getRooms()); QMutexLocker gameListLocker(&gameListMutex); while (roomIterator.hasNext()) { Server_Room *room = roomIterator.next().value(); room->roomMutex.lock(); QMapIterator gameIterator(room->getGames()); while (gameIterator.hasNext()) { Server_Game *game = gameIterator.next().value(); QMutexLocker gameLocker(&game->gameMutex); 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); game->postConnectionStatusUpdate(gamePlayers[j], true); games.insert(game->getGameId(), QPair(game, gamePlayers[j])); Event_GameJoined event1; event1.set_game_id(game->getGameId()); event1.set_game_description(game->getDescription().toStdString()); event1.set_host_id(game->getHostId()); event1.set_player_id(gamePlayers[j]->getPlayerId()); event1.set_spectator(gamePlayers[j]->getSpectator()); event1.set_spectators_can_talk(game->getSpectatorsCanTalk()); event1.set_spectators_see_everything(game->getSpectatorsSeeEverything()); event1.set_resuming(true); rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event1)); Event_GameStateChanged event2; QListIterator gameStateIterator(game->getGameState(gamePlayers[j])); while (gameStateIterator.hasNext()) event2.add_player_list()->CopyFrom(gameStateIterator.next()); event2.set_game_started(game->getGameStarted()); event2.set_active_player_id(game->getActivePlayer()); event2.set_active_phase(game->getActivePhase()); rc.enqueuePostResponseItem(ServerMessage::GAME_EVENT_CONTAINER, game->prepareGameEvent(event2, -1)); break; } } room->roomMutex.unlock(); } server->serverMutex.unlock(); rc.setResponseExtension(re); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdMessage(const Command_Message &cmd, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; QString receiver = QString::fromStdString(cmd.user_name()); Server_ProtocolHandler *userHandler = server->getUsers().value(receiver); if (!userHandler) return Response::RespNameNotFound; if (server->isInIgnoreList(receiver, QString::fromStdString(userInfo->name()))) return Response::RespInIgnoreList; Event_UserMessage event; event.set_sender_name(userInfo->name()); event.set_receiver_name(cmd.user_name()); event.set_message(cmd.message()); SessionEvent *se = prepareSessionEvent(event); userHandler->sendProtocolItem(*se); rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, se); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(const Command_GetGamesOfUser &cmd, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; server->serverMutex.lock(); if (!server->getUsers().contains(QString::fromStdString(cmd.user_name()))) return Response::RespNameNotFound; Response_GetGamesOfUser *re = new Response_GetGamesOfUser; QMapIterator roomIterator(server->getRooms()); while (roomIterator.hasNext()) { Server_Room *room = roomIterator.next().value(); room->roomMutex.lock(); re->add_room_list()->CopyFrom(room->getInfo(false, true)); QListIterator gameIterator(room->getGamesOfUser(QString::fromStdString(cmd.user_name()))); while (gameIterator.hasNext()) re->add_game_list()->CopyFrom(gameIterator.next()); room->roomMutex.unlock(); } server->serverMutex.unlock(); rc.setResponseExtension(re); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetUserInfo &cmd, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; QString userName = QString::fromStdString(cmd.user_name()); Response_GetUserInfo *re = new Response_GetUserInfo; if (userName.isEmpty()) re->mutable_user_info()->CopyFrom(*userInfo); else { Server_ProtocolHandler *handler = server->getUsers().value(userName); if (!handler) return Response::RespNameNotFound; re->mutable_user_info()->CopyFrom(handler->copyUserInfo(true, userInfo->user_level() & ServerInfo_User::IsModerator)); } rc.setResponseExtension(re); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdListRooms(const Command_ListRooms & /*cmd*/, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; Event_ListRooms event; QMapIterator roomIterator(server->getRooms()); while (roomIterator.hasNext()) event.add_room_list()->CopyFrom(roomIterator.next().value()->getInfo(false)); rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event)); acceptsRoomListChanges = true; return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdJoinRoom(const Command_JoinRoom &cmd, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; if (rooms.contains(cmd.room_id())) return Response::RespContextError; Server_Room *r = server->getRooms().value(cmd.room_id(), 0); if (!r) return Response::RespNameNotFound; QMutexLocker serverLocker(&server->serverMutex); QMutexLocker roomLocker(&r->roomMutex); r->addClient(this); rooms.insert(r->getId(), r); Event_RoomSay joinMessageEvent; joinMessageEvent.set_message(r->getJoinMessage().toStdString()); rc.enqueuePostResponseItem(ServerMessage::ROOM_EVENT, r->prepareRoomEvent(joinMessageEvent)); Response_JoinRoom *re = new Response_JoinRoom; re->mutable_room_info()->CopyFrom(r->getInfo(true)); rc.setResponseExtension(re); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUsers & /*cmd*/, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; Response_ListUsers *re = new Response_ListUsers; QMapIterator userIterator = server->getUsers(); while (userIterator.hasNext()) re->add_user_list()->CopyFrom(userIterator.next().value()->copyUserInfo(false)); acceptsUserListChanges = true; rc.setResponseExtension(re); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdLeaveRoom(const Command_LeaveRoom & /*cmd*/, Server_Room *room, ResponseContainer & /*rc*/) { rooms.remove(room->getId()); room->removeClient(this); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdRoomSay(const Command_RoomSay &cmd, Server_Room *room, ResponseContainer & /*rc*/) { QString msg = QString::fromStdString(cmd.message()); if (server->getMessageCountingInterval() > 0) { int totalSize = 0, totalCount = 0; if (messageSizeOverTime.isEmpty()) messageSizeOverTime.prepend(0); messageSizeOverTime[0] += msg.size(); for (int i = 0; i < messageSizeOverTime.size(); ++i) totalSize += messageSizeOverTime[i]; if (messageCountOverTime.isEmpty()) messageCountOverTime.prepend(0); ++messageCountOverTime[0]; for (int i = 0; i < messageCountOverTime.size(); ++i) totalCount += messageCountOverTime[i]; if ((totalSize > server->getMaxMessageSizePerInterval()) || (totalCount > server->getMaxMessageCountPerInterval())) return Response::RespChatFlood; } msg.replace(QChar('\n'), QChar(' ')); room->say(this, msg); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room *room, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; if (server->getMaxGamesPerUser() > 0) if (room->getGamesCreatedByUser(getUserName()) >= server->getMaxGamesPerUser()) return Response::RespContextError; QList gameTypes; for (int i = cmd.game_type_ids_size() - 1; i >= 0; --i) gameTypes.append(cmd.game_type_ids(i)); QString description = QString::fromStdString(cmd.description()); if (description.size() > 60) description = description.left(60); Server_Game *game = room->createGame(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(), this); Server_Player *creator = game->getPlayers().values().first(); QMutexLocker gameListLocker(&gameListMutex); games.insert(game->getGameId(), QPair(game, creator)); 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)); while (gameStateIterator.hasNext()) event2.add_player_list()->CopyFrom(gameStateIterator.next()); 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; } Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGame &cmd, Server_Room *room, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; QMutexLocker gameListLocker(&gameListMutex); if (games.contains(cmd.game_id())) return Response::RespContextError; Server_Game *g = room->getGames().value(cmd.game_id()); if (!g) return Response::RespNameNotFound; QMutexLocker locker(&g->gameMutex); 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()); games.insert(cmd.game_id(), QPair(g, player)); 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)); while (gameStateIterator.hasNext()) event2.add_player_list()->CopyFrom(gameStateIterator.next()); 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)); } return result; } Response::ResponseCode Server_ProtocolHandler::cmdLeaveGame(const Command_LeaveGame & /*cmd*/, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { game->removePlayer(player); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdKickFromGame(const Command_KickFromGame &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { if ((game->getHostId() != player->getPlayerId()) && !(userInfo->user_level() & ServerInfo_User::IsModerator)) return Response::RespFunctionNotAllowed; if (!game->kickPlayer(cmd.player_id())) return Response::RespNameNotFound; return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdDeckSelect(const Command_DeckSelect &cmd, Server_Game * /*game*/, Server_Player *player, ResponseContainer &rc, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; DeckList *deck; if (cmd.has_deck_id()) { try { deck = getDeckFromDatabase(cmd.deck_id()); } catch(Response::ResponseCode r) { return r; } } else deck = new DeckList(QString::fromStdString(cmd.deck())); player->setDeck(deck); Event_PlayerPropertiesChanged event; event.mutable_player_properties()->CopyFrom(player->getProperties()); ges.enqueueGameEvent(event, player->getPlayerId()); Context_DeckSelect context; context.set_deck_hash(deck->getDeckHash().toStdString()); ges.setGameEventContext(context); Response_DeckDownload *re = new Response_DeckDownload; re->set_deck(deck->writeToString_Native().toStdString()); rc.setResponseExtension(re); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdSetSideboardPlan(const Command_SetSideboardPlan &cmd, Server_Game * /*game*/, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (player->getReadyStart()) return Response::RespContextError; DeckList *deck = player->getDeck(); if (!deck) return Response::RespContextError; QList sideboardPlan; for (int i = 0; i < cmd.move_list_size(); ++i) { const MoveCard_ToZone &temp = cmd.move_list(i); sideboardPlan.append(new MoveCardToZone(QString::fromStdString(temp.card_name()), QString::fromStdString(temp.start_zone()), QString::fromStdString(temp.target_zone()))); } deck->setCurrentSideboardPlan(sideboardPlan); for (int i = 0; i < sideboardPlan.size(); ++i) delete sideboardPlan[i]; // XXX TEMPORARY HACK return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdConcede(const Command_Concede & /*cmd*/, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; player->setConceded(true); game->removeArrowsToPlayer(player); player->clearZones(); Event_PlayerPropertiesChanged event; event.mutable_player_properties()->CopyFrom(player->getProperties()); ges.enqueueGameEvent(event, player->getPlayerId()); ges.setGameEventContext(Context_Concede()); game->stopGameIfFinished(); if (game->getGameStarted() && (game->getActivePlayer() == player->getPlayerId())) game->nextTurn(); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdReadyStart(const Command_ReadyStart &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!player->getDeck() || game->getGameStarted()) return Response::RespContextError; if (player->getReadyStart() == cmd.ready()) return Response::RespContextError; player->setReadyStart(cmd.ready()); Event_PlayerPropertiesChanged event; event.mutable_player_properties()->CopyFrom(player->getProperties()); ges.enqueueGameEvent(event, player->getPlayerId()); ges.setGameEventContext(Context_ReadyStart()); game->startGameIfReady(); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdGameSay(const Command_GameSay &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator() && !game->getSpectatorsCanTalk() && !(userInfo->user_level() & ServerInfo_User::IsModerator)) return Response::RespFunctionNotAllowed; Event_GameSay event; event.set_message(cmd.message()); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdShuffle(const Command_Shuffle & /*cmd*/, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; player->getZones().value("deck")->shuffle(); Event_Shuffle event; event.set_zone_name("deck"); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdMulligan(const Command_Mulligan & /*cmd*/, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_CardZone *hand = player->getZones().value("hand"); int number = (hand->cards.size() <= 1) ? player->getInitialCards() : hand->cards.size() - 1; Server_CardZone *deck = player->getZones().value("deck"); while (!hand->cards.isEmpty()) { CardToMove *cardToMove = new CardToMove; cardToMove->set_card_id(hand->cards.first()->getId()); player->moveCard(ges, hand, QList() << cardToMove, deck, 0, 0, false); delete cardToMove; } deck->shuffle(); ges.enqueueGameEvent(Event_Shuffle(), player->getPlayerId()); player->drawCards(ges, number); if (number == player->getInitialCards()) number = -1; Context_Mulligan context; context.set_number(number); ges.setGameEventContext(context); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdRollDie(const Command_RollDie &cmd, Server_Game * /*game*/, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (player->getConceded()) return Response::RespContextError; Event_RollDie event; event.set_sides(cmd.sides()); event.set_value(rng->getNumber(1, cmd.sides())); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdDrawCards(const Command_DrawCards &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; return player->drawCards(ges, cmd.number()); } Response::ResponseCode Server_ProtocolHandler::cmdUndoDraw(const Command_UndoDraw & /*cmd*/, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; return player->undoDraw(ges); } Response::ResponseCode Server_ProtocolHandler::cmdMoveCard(const Command_MoveCard &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; QList cardsToMove; for (int i = 0; i < cmd.cards_to_move().card_size(); ++i) cardsToMove.append(&cmd.cards_to_move().card(i)); return player->moveCard(ges, QString::fromStdString(cmd.start_zone()), cardsToMove, cmd.target_player_id(), QString::fromStdString(cmd.target_zone()), cmd.x(), cmd.y()); } Response::ResponseCode Server_ProtocolHandler::cmdFlipCard(const Command_FlipCard &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_CardZone *zone = player->getZones().value(QString::fromStdString(cmd.zone())); if (!zone) return Response::RespNameNotFound; if (!zone->hasCoords()) return Response::RespContextError; Server_Card *card = zone->getCard(cmd.card_id()); if (!card) return Response::RespNameNotFound; const bool faceDown = cmd.face_down(); if (faceDown == card->getFaceDown()) return Response::RespContextError; card->setFaceDown(faceDown); Event_FlipCard event; event.set_zone_name(zone->getName().toStdString()); event.set_card_id(card->getId()); event.set_card_name(card->getName().toStdString()); event.set_face_down(faceDown); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdAttachCard(const Command_AttachCard &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_CardZone *startzone = player->getZones().value(QString::fromStdString(cmd.start_zone())); if (!startzone) return Response::RespNameNotFound; Server_Card *card = startzone->getCard(cmd.card_id()); if (!card) return Response::RespNameNotFound; Server_Player *targetPlayer = 0; Server_CardZone *targetzone = 0; Server_Card *targetCard = 0; if (cmd.has_target_player_id()) { targetPlayer = game->getPlayer(cmd.target_player_id()); if (!targetPlayer) return Response::RespNameNotFound; } else if (!card->getParentCard()) return Response::RespContextError; if (targetPlayer) targetzone = targetPlayer->getZones().value(QString::fromStdString(cmd.target_zone())); if (targetzone) { // This is currently enough to make sure cards don't get attached to a card that is not on the table. // Possibly a flag will have to be introduced for this sometime. if (!targetzone->hasCoords()) return Response::RespContextError; if (cmd.has_target_card_id()) targetCard = targetzone->getCard(cmd.target_card_id()); if (targetCard) if (targetCard->getParentCard()) return Response::RespContextError; } if (!startzone->hasCoords()) return Response::RespContextError; // Get all arrows pointing to or originating from the card being attached and delete them. QMapIterator playerIterator(game->getPlayers()); while (playerIterator.hasNext()) { Server_Player *p = playerIterator.next().value(); QList arrows = p->getArrows().values(); QList toDelete; for (int i = 0; i < arrows.size(); ++i) { Server_Arrow *a = arrows[i]; Server_Card *tCard = qobject_cast(a->getTargetItem()); if ((tCard == card) || (a->getStartCard() == card)) toDelete.append(a); } for (int i = 0; i < toDelete.size(); ++i) { Event_DeleteArrow event; event.set_arrow_id(toDelete[i]->getId()); ges.enqueueGameEvent(event, p->getPlayerId()); p->deleteArrow(toDelete[i]->getId()); } } if (targetCard) { // Unattach all cards attached to the card being attached. // Make a copy of the list because its contents change during the loop otherwise. QList attachedList = card->getAttachedCards(); for (int i = 0; i < attachedList.size(); ++i) attachedList[i]->getZone()->getPlayer()->unattachCard(ges, attachedList[i]); if (targetzone->isColumnStacked(targetCard->getX(), targetCard->getY())) { CardToMove *cardToMove = new CardToMove; cardToMove->set_card_id(targetCard->getId()); targetPlayer->moveCard(ges, targetzone, QList() << cardToMove, targetzone, targetzone->getFreeGridColumn(-2, targetCard->getY(), targetCard->getName()), targetCard->getY(), targetCard->getFaceDown()); delete cardToMove; } card->setParentCard(targetCard); card->setCoords(-1, card->getY()); Event_AttachCard event; event.set_start_zone(startzone->getName().toStdString()); event.set_card_id(card->getId()); event.set_target_player_id(targetPlayer->getPlayerId()); event.set_target_zone(targetzone->getName().toStdString()); event.set_target_card_id(targetCard->getId()); ges.enqueueGameEvent(event, player->getPlayerId()); startzone->fixFreeSpaces(ges); } else player->unattachCard(ges, card); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdCreateToken(const Command_CreateToken &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_CardZone *zone = player->getZones().value(QString::fromStdString(cmd.zone())); if (!zone) return Response::RespNameNotFound; QString cardName = QString::fromStdString(cmd.card_name()); int x = cmd.x(); int y = cmd.y(); if (zone->hasCoords()) x = zone->getFreeGridColumn(x, y, cardName); if (x < 0) x = 0; if (y < 0) y = 0; Server_Card *card = new Server_Card(cardName, player->newCardId(), x, y); card->moveToThread(player->thread()); card->setPT(QString::fromStdString(cmd.pt())); card->setColor(QString::fromStdString(cmd.color())); card->setAnnotation(QString::fromStdString(cmd.annotation())); card->setDestroyOnZoneChange(cmd.destroy_on_zone_change()); zone->insertCard(card, x, y); Event_CreateToken event; event.set_zone_name(zone->getName().toStdString()); event.set_card_id(card->getId()); event.set_card_name(card->getName().toStdString()); event.set_color(card->getColor().toStdString()); event.set_pt(card->getPT().toStdString()); event.set_annotation(card->getAnnotation().toStdString()); event.set_destroy_on_zone_change(card->getDestroyOnZoneChange()); event.set_x(x); event.set_y(y); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdCreateArrow(const Command_CreateArrow &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_Player *startPlayer = game->getPlayer(cmd.start_player_id()); Server_Player *targetPlayer = game->getPlayer(cmd.target_player_id()); if (!startPlayer || !targetPlayer) return Response::RespNameNotFound; QString startZoneName = QString::fromStdString(cmd.start_zone()); Server_CardZone *startZone = startPlayer->getZones().value(startZoneName); QString targetZoneName = QString::fromStdString(cmd.target_zone()); bool playerTarget = targetZoneName.isEmpty(); Server_CardZone *targetZone = 0; if (!playerTarget) targetZone = targetPlayer->getZones().value(targetZoneName); if (!startZone || (!targetZone && !playerTarget)) return Response::RespNameNotFound; if (startZone->getType() != ServerInfo_Zone::PublicZone) return Response::RespContextError; Server_Card *startCard = startZone->getCard(cmd.start_card_id()); if (!startCard) return Response::RespNameNotFound; Server_Card *targetCard = 0; if (!playerTarget) { if (targetZone->getType() != ServerInfo_Zone::PublicZone) return Response::RespContextError; targetCard = targetZone->getCard(cmd.target_card_id()); } Server_ArrowTarget *targetItem; if (playerTarget) targetItem = targetPlayer; else targetItem = targetCard; if (!targetItem) return Response::RespNameNotFound; QMapIterator arrowIterator(player->getArrows()); while (arrowIterator.hasNext()) { Server_Arrow *temp = arrowIterator.next().value(); if ((temp->getStartCard() == startCard) && (temp->getTargetItem() == targetItem)) return Response::RespContextError; } Server_Arrow *arrow = new Server_Arrow(player->newArrowId(), startCard, targetItem, cmd.arrow_color()); player->addArrow(arrow); Event_CreateArrow event; ServerInfo_Arrow *arrowInfo = event.mutable_arrow_info(); arrowInfo->set_id(arrow->getId()); arrowInfo->set_start_player_id(startPlayer->getPlayerId()); arrowInfo->set_start_zone(startZoneName.toStdString()); arrowInfo->set_start_card_id(startCard->getId()); arrowInfo->set_target_player_id(targetPlayer->getPlayerId()); arrowInfo->set_target_zone(targetZoneName.toStdString()); arrowInfo->set_target_card_id(cmd.target_card_id()); arrowInfo->mutable_arrow_color()->CopyFrom(cmd.arrow_color()); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdDeleteArrow(const Command_DeleteArrow &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; if (!player->deleteArrow(cmd.arrow_id())) return Response::RespNameNotFound; Event_DeleteArrow event; event.set_arrow_id(cmd.arrow_id()); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdSetCardAttr(const Command_SetCardAttr &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; return player->setCardAttrHelper(ges, QString::fromStdString(cmd.zone()), cmd.card_id(), cmd.attribute(), QString::fromStdString(cmd.attr_value())); } Response::ResponseCode Server_ProtocolHandler::cmdSetCardCounter(const Command_SetCardCounter &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_CardZone *zone = player->getZones().value(QString::fromStdString(cmd.zone())); if (!zone) return Response::RespNameNotFound; if (!zone->hasCoords()) return Response::RespContextError; Server_Card *card = zone->getCard(cmd.card_id()); if (!card) return Response::RespNameNotFound; card->setCounter(cmd.counter_id(), cmd.counter_value()); Event_SetCardCounter event; event.set_zone_name(zone->getName().toStdString()); event.set_card_id(card->getId()); event.set_counter_id(cmd.counter_id()); event.set_counter_value(cmd.counter_value()); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdIncCardCounter(const Command_IncCardCounter &cmd, Server_Game *game, Server_Player *player, ResponseContainer &/*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_CardZone *zone = player->getZones().value(QString::fromStdString(cmd.zone())); if (!zone) return Response::RespNameNotFound; if (!zone->hasCoords()) return Response::RespContextError; Server_Card *card = zone->getCard(cmd.card_id()); if (!card) return Response::RespNameNotFound; int newValue = card->getCounter(cmd.counter_id()) + cmd.counter_delta(); card->setCounter(cmd.counter_id(), newValue); Event_SetCardCounter event; event.set_zone_name(zone->getName().toStdString()); event.set_card_id(card->getId()); event.set_counter_id(cmd.counter_id()); event.set_counter_value(newValue); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdIncCounter(const Command_IncCounter &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; const QMap counters = player->getCounters(); Server_Counter *c = counters.value(cmd.counter_id(), 0); if (!c) return Response::RespNameNotFound; c->setCount(c->getCount() + cmd.delta()); Event_SetCounter event; event.set_counter_id(c->getId()); event.set_value(c->getCount()); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdCreateCounter(const Command_CreateCounter &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_Counter *c = new Server_Counter(player->newCounterId(), QString::fromStdString(cmd.counter_name()), cmd.counter_color(), cmd.radius(), cmd.value()); player->addCounter(c); Event_CreateCounter event; ServerInfo_Counter *counterInfo = event.mutable_counter_info(); counterInfo->set_id(c->getId()); counterInfo->set_name(c->getName().toStdString()); counterInfo->mutable_counter_color()->CopyFrom(cmd.counter_color()); counterInfo->set_radius(c->getRadius()); counterInfo->set_count(c->getCount()); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdSetCounter(const Command_SetCounter &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_Counter *c = player->getCounters().value(cmd.counter_id(), 0);; if (!c) return Response::RespNameNotFound; c->setCount(cmd.value()); Event_SetCounter event; event.set_counter_id(c->getId()); event.set_value(c->getCount()); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdDelCounter(const Command_DelCounter &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; if (!player->deleteCounter(cmd.counter_id())) return Response::RespNameNotFound; Event_DelCounter event; event.set_counter_id(cmd.counter_id()); ges.enqueueGameEvent(event, player->getPlayerId()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdNextTurn(const Command_NextTurn & /*cmd*/, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; game->nextTurn(); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdSetActivePhase(const Command_SetActivePhase &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; if (game->getActivePlayer() != player->getPlayerId()) return Response::RespContextError; game->setActivePhase(cmd.phase()); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdDumpZone(const Command_DumpZone &cmd, Server_Game *game, Server_Player *player, ResponseContainer &rc, GameEventStorage &ges) { if (!game->getGameStarted()) return Response::RespGameNotStarted; Server_Player *otherPlayer = game->getPlayer(cmd.player_id()); if (!otherPlayer) return Response::RespNameNotFound; Server_CardZone *zone = otherPlayer->getZones().value(QString::fromStdString(cmd.zone_name())); if (!zone) return Response::RespNameNotFound; if (!((zone->getType() == ServerInfo_Zone::PublicZone) || (player == otherPlayer))) return Response::RespContextError; int numberCards = cmd.number_cards(); Response_DumpZone *re = new Response_DumpZone; ServerInfo_Zone *zoneInfo = re->mutable_zone_info(); zoneInfo->set_name(zone->getName().toStdString()); zoneInfo->set_type(zone->getType()); zoneInfo->set_with_coords(zone->hasCoords()); zoneInfo->set_card_count(numberCards < zone->cards.size() ? zone->cards.size() : numberCards); for (int i = 0; (i < zone->cards.size()) && (i < numberCards || numberCards == -1); ++i) { Server_Card *card = zone->cards[i]; QString displayedName = card->getFaceDown() ? QString() : card->getName(); ServerInfo_Card *cardInfo = zoneInfo->add_card_list(); cardInfo->set_name(displayedName.toStdString()); if (zone->getType() == ServerInfo_Zone::HiddenZone) cardInfo->set_id(i); else { cardInfo->set_id(card->getId()); cardInfo->set_x(card->getX()); cardInfo->set_y(card->getY()); cardInfo->set_face_down(card->getFaceDown()); cardInfo->set_tapped(card->getTapped()); cardInfo->set_attacking(card->getAttacking()); cardInfo->set_color(card->getColor().toStdString()); cardInfo->set_pt(card->getPT().toStdString()); cardInfo->set_annotation(card->getAnnotation().toStdString()); cardInfo->set_destroy_on_zone_change(card->getDestroyOnZoneChange()); cardInfo->set_doesnt_untap(card->getDoesntUntap()); QMapIterator cardCounterIterator(card->getCounters()); while (cardCounterIterator.hasNext()) { cardCounterIterator.next(); ServerInfo_CardCounter *counterInfo = cardInfo->add_counter_list(); counterInfo->set_id(cardCounterIterator.key()); counterInfo->set_value(cardCounterIterator.value()); } if (card->getParentCard()) { cardInfo->set_attach_player_id(card->getParentCard()->getZone()->getPlayer()->getPlayerId()); cardInfo->set_attach_zone(card->getParentCard()->getZone()->getName().toStdString()); cardInfo->set_attach_card_id(card->getParentCard()->getId()); } } } if (zone->getType() == ServerInfo_Zone::HiddenZone) { zone->setCardsBeingLookedAt(numberCards); Event_DumpZone event; event.set_zone_owner_id(otherPlayer->getPlayerId()); event.set_zone_name(zone->getName().toStdString()); event.set_number_cards(numberCards); ges.enqueueGameEvent(event, player->getPlayerId()); } rc.setResponseExtension(re); return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdStopDumpZone(const Command_StopDumpZone &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_Player *otherPlayer = game->getPlayer(cmd.player_id()); if (!otherPlayer) return Response::RespNameNotFound; Server_CardZone *zone = otherPlayer->getZones().value(QString::fromStdString(cmd.zone_name())); if (!zone) return Response::RespNameNotFound; if (zone->getType() == ServerInfo_Zone::HiddenZone) { zone->setCardsBeingLookedAt(0); Event_StopDumpZone event; event.set_zone_owner_id(cmd.player_id()); event.set_zone_name(zone->getName().toStdString()); ges.enqueueGameEvent(event, player->getPlayerId()); } return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdRevealCards(const Command_RevealCards &cmd, Server_Game *game, Server_Player *player, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (player->getSpectator()) return Response::RespFunctionNotAllowed; if (!game->getGameStarted()) return Response::RespGameNotStarted; if (player->getConceded()) return Response::RespContextError; Server_Player *otherPlayer = 0; if (cmd.has_player_id()) { otherPlayer = game->getPlayer(cmd.player_id()); if (!otherPlayer) return Response::RespNameNotFound; } Server_CardZone *zone = player->getZones().value(QString::fromStdString(cmd.zone_name())); if (!zone) return Response::RespNameNotFound; QList cardsToReveal; if (!cmd.has_card_id()) cardsToReveal = zone->cards; else if (cmd.card_id() == -2) { if (zone->cards.isEmpty()) return Response::RespContextError; cardsToReveal.append(zone->cards.at(rng->getNumber(0, zone->cards.size() - 1))); } else { Server_Card *card = zone->getCard(cmd.card_id()); if (!card) return Response::RespNameNotFound; cardsToReveal.append(card); } Event_RevealCards eventOthers; eventOthers.set_zone_name(zone->getName().toStdString()); if (cmd.has_card_id()) eventOthers.set_card_id(cmd.card_id()); if (cmd.has_player_id()) eventOthers.set_other_player_id(cmd.player_id()); Event_RevealCards eventPrivate(eventOthers); for (int i = 0; i < cardsToReveal.size(); ++i) { Server_Card *card = cardsToReveal[i]; ServerInfo_Card *cardInfo = eventPrivate.add_cards(); cardInfo->set_id(card->getId()); cardInfo->set_name(card->getName().toStdString()); cardInfo->set_x(card->getX()); cardInfo->set_y(card->getY()); cardInfo->set_face_down(card->getFaceDown()); cardInfo->set_tapped(card->getTapped()); cardInfo->set_attacking(card->getAttacking()); cardInfo->set_color(card->getColor().toStdString()); cardInfo->set_pt(card->getPT().toStdString()); cardInfo->set_annotation(card->getAnnotation().toStdString()); cardInfo->set_destroy_on_zone_change(card->getDestroyOnZoneChange()); cardInfo->set_doesnt_untap(card->getDoesntUntap()); QMapIterator cardCounterIterator(card->getCounters()); while (cardCounterIterator.hasNext()) { cardCounterIterator.next(); ServerInfo_CardCounter *counterInfo = cardInfo->add_counter_list(); counterInfo->set_id(cardCounterIterator.key()); counterInfo->set_value(cardCounterIterator.value()); } if (card->getParentCard()) { cardInfo->set_attach_player_id(card->getParentCard()->getZone()->getPlayer()->getPlayerId()); cardInfo->set_attach_zone(card->getParentCard()->getZone()->getName().toStdString()); cardInfo->set_attach_card_id(card->getParentCard()->getId()); } } if (cmd.has_player_id()) { ges.enqueueGameEvent(eventPrivate, player->getPlayerId(), GameEventStorageItem::SendToPrivate, cmd.player_id()); ges.enqueueGameEvent(eventOthers, player->getPlayerId(), GameEventStorageItem::SendToOthers); } else ges.enqueueGameEvent(eventPrivate, player->getPlayerId()); return Response::RespOk; }