#include "server_abstract_participant.h" #include "../../color.h" #include "../../deck_list.h" #include "../../deck_list_card_node.h" #include "../../get_pb_extension.h" #include "../../rng_abstract.h" #include "../../trice_limits.h" #include "../server.h" #include "../server_abstractuserinterface.h" #include "../server_database_interface.h" #include "../server_room.h" #include "pb/command_attach_card.pb.h" #include "pb/command_change_zone_properties.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_reverse_turn.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_lock.pb.h" #include "pb/command_set_sideboard_plan.pb.h" #include "pb/command_shuffle.pb.h" #include "pb/command_undo_draw.pb.h" #include "pb/context_concede.pb.h" #include "pb/context_connection_state_changed.pb.h" #include "pb/context_deck_select.pb.h" #include "pb/context_move_card.pb.h" #include "pb/context_mulligan.pb.h" #include "pb/context_ready_start.pb.h" #include "pb/context_set_sideboard_lock.pb.h" #include "pb/context_undo_draw.pb.h" #include "pb/event_attach_card.pb.h" #include "pb/event_change_zone_properties.pb.h" #include "pb/event_create_arrow.pb.h" #include "pb/event_create_counter.pb.h" #include "pb/event_create_token.pb.h" #include "pb/event_del_counter.pb.h" #include "pb/event_delete_arrow.pb.h" #include "pb/event_destroy_card.pb.h" #include "pb/event_draw_cards.pb.h" #include "pb/event_dump_zone.pb.h" #include "pb/event_flip_card.pb.h" #include "pb/event_game_say.pb.h" #include "pb/event_move_card.pb.h" #include "pb/event_player_properties_changed.pb.h" #include "pb/event_reveal_cards.pb.h" #include "pb/event_reverse_turn.pb.h" #include "pb/event_roll_die.pb.h" #include "pb/event_set_card_attr.pb.h" #include "pb/event_set_card_counter.pb.h" #include "pb/event_set_counter.pb.h" #include "pb/event_shuffle.pb.h" #include "pb/response.pb.h" #include "pb/response_deck_download.pb.h" #include "pb/response_dump_zone.pb.h" #include "pb/serverinfo_player.pb.h" #include "pb/serverinfo_user.pb.h" #include "server_arrow.h" #include "server_card.h" #include "server_cardzone.h" #include "server_counter.h" #include "server_game.h" #include "server_player.h" #include #include #include Server_AbstractParticipant::Server_AbstractParticipant(Server_Game *_game, int _playerId, const ServerInfo_User &_userInfo, bool _judge, Server_AbstractUserInterface *_userInterface) : ServerInfo_User_Container(_userInfo), game(_game), userInterface(_userInterface), pingTime(0), playerId(_playerId), judge(_judge) { } Server_AbstractParticipant::~Server_AbstractParticipant() = default; void Server_AbstractParticipant::removeFromGame() { QMutexLocker locker(&playerMutex); if (userInterface) { userInterface->playerRemovedFromGame(game); } } bool Server_AbstractParticipant::updatePingTime() // returns true if ping time changed { QMutexLocker locker(&playerMutex); int oldPingTime = pingTime; if (userInterface) { pingTime = userInterface->getLastCommandTime(); } else { pingTime = -1; } return pingTime != oldPingTime; } void Server_AbstractParticipant::getProperties(ServerInfo_PlayerProperties &result, bool withUserInfo) { result.set_player_id(playerId); if (withUserInfo) { copyUserInfo(*(result.mutable_user_info()), true); } result.set_spectator(spectator); result.set_judge(judge); result.set_ping_seconds(pingTime); getPlayerProperties(result); } void Server_AbstractParticipant::getPlayerProperties(ServerInfo_PlayerProperties & /*result*/) { } Response::ResponseCode Server_AbstractParticipant::cmdLeaveGame(const Command_LeaveGame & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { game->removeParticipant(this, Event_Leave::USER_LEFT); return Response::RespOk; } Response::ResponseCode Server_AbstractParticipant::cmdKickFromGame(const Command_KickFromGame &cmd, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { if ((game->getHostId() != playerId) && !(userInfo->user_level() & ServerInfo_User::IsModerator)) { return Response::RespFunctionNotAllowed; } if (!game->kickParticipant(cmd.player_id())) { return Response::RespNameNotFound; } return Response::RespOk; } Response::ResponseCode Server_AbstractParticipant::cmdDeckSelect(const Command_DeckSelect & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdSetSideboardPlan(const Command_SetSideboardPlan & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdSetSideboardLock(const Command_SetSideboardLock & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdConcede(const Command_Concede & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdUnconcede(const Command_Unconcede & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdJudge(const Command_Judge &cmd, ResponseContainer &rc, GameEventStorage &ges) { if (!judge) { return Response::RespFunctionNotAllowed; } Server_Player *player = this->game->getPlayer(cmd.target_id()); ges.setForcedByJudge(playerId); if (player == nullptr) { return Response::RespContextError; } for (int i = 0; i < cmd.game_command_size(); ++i) { player->processGameCommand(cmd.game_command(i), rc, ges); } return Response::RespOk; } Response::ResponseCode Server_AbstractParticipant::cmdReadyStart(const Command_ReadyStart & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdGameSay(const Command_GameSay &cmd, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (spectator) { /* Spectators can only talk if: * (a) the game creator allows it * (b) the spectator is a moderator/administrator * (c) the spectator is a judge */ bool isModOrJudge = (userInfo->user_level() & (ServerInfo_User::IsModerator | ServerInfo_User::IsJudge)); if (!isModOrJudge && !game->getSpectatorsCanTalk()) { return Response::RespFunctionNotAllowed; } } if (!userInterface->addSaidMessageSize(static_cast(cmd.message().size()))) { return Response::RespChatFlood; } Event_GameSay event; event.set_message(cmd.message()); ges.enqueueGameEvent(event, playerId); game->getRoom()->getServer()->getDatabaseInterface()->logMessage( userInfo->id(), QString::fromStdString(userInfo->name()), QString::fromStdString(userInfo->address()), textFromStdString(cmd.message()), Server_DatabaseInterface::MessageTargetGame, game->getGameId(), game->getDescription()); return Response::RespOk; } Response::ResponseCode Server_AbstractParticipant::cmdShuffle(const Command_Shuffle & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdMulligan(const Command_Mulligan & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdRollDie(const Command_RollDie & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) const { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdDrawCards(const Command_DrawCards & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdUndoDraw(const Command_UndoDraw & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdMoveCard(const Command_MoveCard & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdFlipCard(const Command_FlipCard & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdAttachCard(const Command_AttachCard & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdCreateToken(const Command_CreateToken & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdCreateArrow(const Command_CreateArrow & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdDeleteArrow(const Command_DeleteArrow & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdSetCardAttr(const Command_SetCardAttr & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdSetCardCounter(const Command_SetCardCounter & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdIncCardCounter(const Command_IncCardCounter & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdIncCounter(const Command_IncCounter & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdCreateCounter(const Command_CreateCounter & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdSetCounter(const Command_SetCounter & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdDelCounter(const Command_DelCounter & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdNextTurn(const Command_NextTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { if (!game->getGameStarted()) { return Response::RespGameNotStarted; } if (!judge) { return Response::RespFunctionNotAllowed; } game->nextTurn(); return Response::RespOk; } Response::ResponseCode Server_AbstractParticipant::cmdSetActivePhase(const Command_SetActivePhase &cmd, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { if (!game->getGameStarted()) { return Response::RespGameNotStarted; } if (!judge) { return Response::RespFunctionNotAllowed; } game->setActivePhase(cmd.phase()); return Response::RespOk; } Response::ResponseCode Server_AbstractParticipant::cmdDumpZone(const Command_DumpZone & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdRevealCards(const Command_RevealCards & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdChangeZoneProperties(const Command_ChangeZoneProperties & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage & /*ges*/) { return Response::RespFunctionNotAllowed; } Response::ResponseCode Server_AbstractParticipant::cmdReverseTurn(const Command_ReverseTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges) { if (!judge) { if (spectator) { return Response::RespFunctionNotAllowed; } if (!game->getGameStarted()) { return Response::RespGameNotStarted; } } bool reversedTurn = game->reverseTurnOrder(); Event_ReverseTurn event; event.set_reversed(reversedTurn); ges.enqueueGameEvent(event, playerId); return Response::RespOk; } Response::ResponseCode Server_AbstractParticipant::processGameCommand(const GameCommand &command, ResponseContainer &rc, GameEventStorage &ges) { switch ((GameCommand::GameCommandType)getPbExtension(command)) { case GameCommand::KICK_FROM_GAME: return cmdKickFromGame(command.GetExtension(Command_KickFromGame::ext), rc, ges); break; case GameCommand::LEAVE_GAME: return cmdLeaveGame(command.GetExtension(Command_LeaveGame::ext), rc, ges); break; case GameCommand::GAME_SAY: return cmdGameSay(command.GetExtension(Command_GameSay::ext), rc, ges); break; case GameCommand::SHUFFLE: return cmdShuffle(command.GetExtension(Command_Shuffle::ext), rc, ges); break; case GameCommand::MULLIGAN: return cmdMulligan(command.GetExtension(Command_Mulligan::ext), rc, ges); break; case GameCommand::ROLL_DIE: return cmdRollDie(command.GetExtension(Command_RollDie::ext), rc, ges); break; case GameCommand::DRAW_CARDS: return cmdDrawCards(command.GetExtension(Command_DrawCards::ext), rc, ges); break; case GameCommand::UNDO_DRAW: return cmdUndoDraw(command.GetExtension(Command_UndoDraw::ext), rc, ges); break; case GameCommand::FLIP_CARD: return cmdFlipCard(command.GetExtension(Command_FlipCard::ext), rc, ges); break; case GameCommand::ATTACH_CARD: return cmdAttachCard(command.GetExtension(Command_AttachCard::ext), rc, ges); break; case GameCommand::CREATE_TOKEN: return cmdCreateToken(command.GetExtension(Command_CreateToken::ext), rc, ges); break; case GameCommand::CREATE_ARROW: return cmdCreateArrow(command.GetExtension(Command_CreateArrow::ext), rc, ges); break; case GameCommand::DELETE_ARROW: return cmdDeleteArrow(command.GetExtension(Command_DeleteArrow::ext), rc, ges); break; case GameCommand::SET_CARD_ATTR: return cmdSetCardAttr(command.GetExtension(Command_SetCardAttr::ext), rc, ges); break; case GameCommand::SET_CARD_COUNTER: return cmdSetCardCounter(command.GetExtension(Command_SetCardCounter::ext), rc, ges); break; case GameCommand::INC_CARD_COUNTER: return cmdIncCardCounter(command.GetExtension(Command_IncCardCounter::ext), rc, ges); break; case GameCommand::READY_START: return cmdReadyStart(command.GetExtension(Command_ReadyStart::ext), rc, ges); break; case GameCommand::CONCEDE: return cmdConcede(command.GetExtension(Command_Concede::ext), rc, ges); break; case GameCommand::INC_COUNTER: return cmdIncCounter(command.GetExtension(Command_IncCounter::ext), rc, ges); break; case GameCommand::CREATE_COUNTER: return cmdCreateCounter(command.GetExtension(Command_CreateCounter::ext), rc, ges); break; case GameCommand::SET_COUNTER: return cmdSetCounter(command.GetExtension(Command_SetCounter::ext), rc, ges); break; case GameCommand::DEL_COUNTER: return cmdDelCounter(command.GetExtension(Command_DelCounter::ext), rc, ges); break; case GameCommand::NEXT_TURN: return cmdNextTurn(command.GetExtension(Command_NextTurn::ext), rc, ges); break; case GameCommand::SET_ACTIVE_PHASE: return cmdSetActivePhase(command.GetExtension(Command_SetActivePhase::ext), rc, ges); break; case GameCommand::DUMP_ZONE: return cmdDumpZone(command.GetExtension(Command_DumpZone::ext), rc, ges); break; case GameCommand::REVEAL_CARDS: return cmdRevealCards(command.GetExtension(Command_RevealCards::ext), rc, ges); break; case GameCommand::MOVE_CARD: return cmdMoveCard(command.GetExtension(Command_MoveCard::ext), rc, ges); break; case GameCommand::SET_SIDEBOARD_PLAN: return cmdSetSideboardPlan(command.GetExtension(Command_SetSideboardPlan::ext), rc, ges); break; case GameCommand::DECK_SELECT: return cmdDeckSelect(command.GetExtension(Command_DeckSelect::ext), rc, ges); break; case GameCommand::SET_SIDEBOARD_LOCK: return cmdSetSideboardLock(command.GetExtension(Command_SetSideboardLock::ext), rc, ges); break; case GameCommand::CHANGE_ZONE_PROPERTIES: return cmdChangeZoneProperties(command.GetExtension(Command_ChangeZoneProperties::ext), rc, ges); break; case GameCommand::UNCONCEDE: return cmdUnconcede(command.GetExtension(Command_Unconcede::ext), rc, ges); break; case GameCommand::JUDGE: return cmdJudge(command.GetExtension(Command_Judge::ext), rc, ges); break; case GameCommand::REVERSE_TURN: return cmdReverseTurn(command.GetExtension(Command_ReverseTurn::ext), rc, ges); break; default: return Response::RespInvalidCommand; } } void Server_AbstractParticipant::sendGameEvent(const GameEventContainer &cont) { QMutexLocker locker(&playerMutex); if (userInterface) { userInterface->sendProtocolItem(cont); } } void Server_AbstractParticipant::setUserInterface(Server_AbstractUserInterface *_userInterface) { playerMutex.lock(); userInterface = _userInterface; playerMutex.unlock(); pingTime = _userInterface ? 0 : -1; Event_PlayerPropertiesChanged event; event.mutable_player_properties()->set_ping_seconds(pingTime); GameEventStorage ges; ges.setGameEventContext(Context_ConnectionStateChanged()); ges.enqueueGameEvent(event, playerId); ges.sendToGame(game); } void Server_AbstractParticipant::disconnectClient() { bool isRegistered = userInfo->user_level() & ServerInfo_User::IsRegistered; if (!isRegistered || spectator) { game->removeParticipant(this, Event_Leave::USER_DISCONNECTED); } else { setUserInterface(nullptr); } } void Server_AbstractParticipant::getInfo(ServerInfo_Player *info, Server_AbstractParticipant * /*recipient*/, bool /* omniscient */, bool withUserInfo) { getProperties(*info->mutable_properties(), withUserInfo); }