* move common server files

* update includes with move

* create participant, move code

* fix linker errors

* fix regressions

* mark function as override to make clang happy

* split out spectator to new file

* forgot to add to cmakelists

* autocompleter picking wrong casing for var name

* clean up forwards declarations in player

* fix includes in game
This commit is contained in:
ebbit1q 2025-09-20 14:37:12 +02:00 committed by GitHub
parent 17dcaf9afa
commit f0c3860032
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 1283 additions and 866 deletions

View file

@ -0,0 +1,612 @@
#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 <QDebug>
#include <QRegularExpression>
#include <algorithm>
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<int>(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);
}

View file

@ -0,0 +1,183 @@
#ifndef ABSTRACT_PARTICIPANT_H
#define ABSTRACT_PARTICIPANT_H
#include "../../serverinfo_user_container.h"
#include "pb/card_attributes.pb.h"
#include "pb/response.pb.h"
#include "server_arrowtarget.h"
#include <QMutex>
class Server_Game;
class Server_AbstractUserInterface;
class ServerInfo_User;
class ServerInfo_Player;
class ServerInfo_PlayerProperties;
class GameEventContainer;
class GameEventStorage;
class ResponseContainer;
class GameCommand;
class Command_KickFromGame;
class Command_LeaveGame;
class Command_GameSay;
class Command_Shuffle;
class Command_Mulligan;
class Command_RollDie;
class Command_DrawCards;
class Command_UndoDraw;
class Command_FlipCard;
class Command_AttachCard;
class Command_CreateToken;
class Command_CreateArrow;
class Command_DeleteArrow;
class Command_SetCardAttr;
class Command_SetCardCounter;
class Command_IncCardCounter;
class Command_ReadyStart;
class Command_Concede;
class Command_Unconcede;
class Command_Judge;
class Command_IncCounter;
class Command_CreateCounter;
class Command_SetCounter;
class Command_DelCounter;
class Command_NextTurn;
class Command_SetActivePhase;
class Command_DumpZone;
class Command_RevealCards;
class Command_ReverseTurn;
class Command_MoveCard;
class Command_SetSideboardPlan;
class Command_DeckSelect;
class Command_SetSideboardLock;
class Command_ChangeZoneProperties;
class Server_AbstractParticipant : public Server_ArrowTarget, public ServerInfo_User_Container
{
Q_OBJECT
protected:
Server_Game *game;
Server_AbstractUserInterface *userInterface;
int pingTime;
int playerId;
bool spectator;
bool judge;
virtual void getPlayerProperties(ServerInfo_PlayerProperties &result);
mutable QMutex playerMutex;
public:
Server_AbstractParticipant(Server_Game *_game,
int _playerId,
const ServerInfo_User &_userInfo,
bool _judge,
Server_AbstractUserInterface *_handler);
~Server_AbstractParticipant() override;
virtual void prepareDestroy()
{
removeFromGame();
};
void removeFromGame();
Server_AbstractUserInterface *getUserInterface() const
{
return userInterface;
}
void setUserInterface(Server_AbstractUserInterface *_userInterface);
void disconnectClient();
int getPlayerId() const
{
return playerId;
}
bool getSpectator() const
{
return spectator;
}
bool getJudge() const
{
return judge;
}
Server_Game *getGame() const
{
return game;
}
int getPingTime() const
{
return pingTime;
}
bool updatePingTime();
void getProperties(ServerInfo_PlayerProperties &result, bool withUserInfo);
virtual Response::ResponseCode
cmdLeaveGame(const Command_LeaveGame &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdKickFromGame(const Command_KickFromGame &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode cmdConcede(const Command_Concede &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdUnconcede(const Command_Unconcede &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode cmdJudge(const Command_Judge &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdSetSideboardPlan(const Command_SetSideboardPlan &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdSetSideboardLock(const Command_SetSideboardLock &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode cmdGameSay(const Command_GameSay &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode cmdShuffle(const Command_Shuffle &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdMulligan(const Command_Mulligan &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdRollDie(const Command_RollDie &cmd, ResponseContainer &rc, GameEventStorage &ges) const;
virtual Response::ResponseCode
cmdDrawCards(const Command_DrawCards &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdUndoDraw(const Command_UndoDraw &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdMoveCard(const Command_MoveCard &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdFlipCard(const Command_FlipCard &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdCreateArrow(const Command_CreateArrow &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdDeleteArrow(const Command_DeleteArrow &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdSetCardAttr(const Command_SetCardAttr &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdSetCardCounter(const Command_SetCardCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdIncCardCounter(const Command_IncCardCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdIncCounter(const Command_IncCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdCreateCounter(const Command_CreateCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdSetCounter(const Command_SetCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdDelCounter(const Command_DelCounter &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdNextTurn(const Command_NextTurn &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdSetActivePhase(const Command_SetActivePhase &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdDumpZone(const Command_DumpZone &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdRevealCards(const Command_RevealCards &cmd, ResponseContainer &rc, GameEventStorage &ges);
virtual Response::ResponseCode
cmdReverseTurn(const Command_ReverseTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges);
virtual Response::ResponseCode
cmdChangeZoneProperties(const Command_ChangeZoneProperties &cmd, ResponseContainer &rc, GameEventStorage &ges);
Response::ResponseCode processGameCommand(const GameCommand &command, ResponseContainer &rc, GameEventStorage &ges);
void sendGameEvent(const GameEventContainer &event);
virtual void
getInfo(ServerInfo_Player *info, Server_AbstractParticipant *recipient, bool omniscient, bool withUserInfo);
};
#endif

View file

@ -0,0 +1,28 @@
#include "server_arrow.h"
#include "pb/serverinfo_arrow.pb.h"
#include "server_card.h"
#include "server_cardzone.h"
#include "server_player.h"
Server_Arrow::Server_Arrow(int _id, Server_Card *_startCard, Server_ArrowTarget *_targetItem, const color &_arrowColor)
: id(_id), startCard(_startCard), targetItem(_targetItem), arrowColor(_arrowColor)
{
}
void Server_Arrow::getInfo(ServerInfo_Arrow *info)
{
info->set_id(id);
info->set_start_player_id(startCard->getZone()->getPlayer()->getPlayerId());
info->set_start_zone(startCard->getZone()->getName().toStdString());
info->set_start_card_id(startCard->getId());
info->mutable_arrow_color()->CopyFrom(arrowColor);
Server_Card *targetCard = qobject_cast<Server_Card *>(targetItem);
if (targetCard) {
info->set_target_player_id(targetCard->getZone()->getPlayer()->getPlayerId());
info->set_target_zone(targetCard->getZone()->getName().toStdString());
info->set_target_card_id(targetCard->getId());
} else
info->set_target_player_id(static_cast<Server_Player *>(targetItem)->getPlayerId());
}

View file

@ -0,0 +1,52 @@
#ifndef SERVER_ARROW_H
#define SERVER_ARROW_H
#include "pb/color.pb.h"
class Server_Card;
class Server_ArrowTarget;
class ServerInfo_Arrow;
class Server_Arrow
{
private:
int id;
Server_Card *startCard;
Server_ArrowTarget *targetItem;
color arrowColor;
public:
Server_Arrow(int _id, Server_Card *_startCard, Server_ArrowTarget *_targetItem, const color &_arrowColor);
int getId() const
{
return id;
}
void setId(int _id)
{
id = _id;
}
Server_Card *getStartCard() const
{
return startCard;
}
void setStartCard(Server_Card *startCard_)
{
startCard = startCard_;
}
Server_ArrowTarget *getTargetItem() const
{
return targetItem;
}
void setTargetItem(Server_ArrowTarget *targetItem_)
{
targetItem = targetItem_;
}
const color &getColor() const
{
return arrowColor;
}
void getInfo(ServerInfo_Arrow *info);
};
#endif

View file

@ -0,0 +1,2 @@
#include "server_arrowtarget.h"

View file

@ -0,0 +1,11 @@
#ifndef SERVER_ARROWTARGET_H
#define SERVER_ARROWTARGET_H
#include <QObject>
class Server_ArrowTarget : public QObject
{
Q_OBJECT
};
#endif

View file

@ -0,0 +1,174 @@
/***************************************************************************
* Copyright (C) 2008 by Max-Wilhelm Bruker *
* brukie@laptop *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "server_card.h"
#include "pb/event_set_card_attr.pb.h"
#include "pb/event_set_card_counter.pb.h"
#include "pb/serverinfo_card.pb.h"
#include "server_cardzone.h"
#include "server_player.h"
#include <QVariant>
Server_Card::Server_Card(const CardRef &cardRef, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone)
: zone(_zone), id(_id), coord_x(_coord_x), coord_y(_coord_y), cardRef(cardRef), tapped(false), attacking(false),
facedown(false), destroyOnZoneChange(false), doesntUntap(false), parentCard(0), stashedCard(nullptr)
{
}
Server_Card::~Server_Card()
{
// setParentCard(0) leads to the item being removed from our list, so we can't iterate properly
while (!attachedCards.isEmpty())
attachedCards.first()->setParentCard(0);
if (parentCard)
parentCard->removeAttachedCard(this);
if (stashedCard) {
stashedCard->deleteLater();
stashedCard = nullptr;
}
}
void Server_Card::resetState(bool keepAnnotations)
{
counters.clear();
setTapped(false);
setAttacking(false);
setPT(QString());
if (!keepAnnotations) {
setAnnotation(QString());
}
setDoesntUntap(false);
}
QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue, bool allCards)
{
if (attribute == AttrTapped && avalue != "1" && allCards && doesntUntap)
return QVariant(tapped).toString();
return setAttribute(attribute, avalue);
}
QString Server_Card::setAttribute(CardAttribute attribute, const QString &avalue, Event_SetCardAttr *event)
{
if (event)
event->set_attribute(attribute);
switch (attribute) {
case AttrTapped: {
setTapped(avalue == "1");
break;
}
case AttrAttacking:
setAttacking(avalue == "1");
break;
case AttrFaceDown:
setFaceDown(avalue == "1");
break;
case AttrColor:
setColor(avalue);
break;
case AttrPT:
setPT(avalue);
if (event)
event->set_attr_value(getPT().toStdString());
return getPT();
case AttrAnnotation:
setAnnotation(avalue);
break;
case AttrDoesntUntap:
setDoesntUntap(avalue == "1");
break;
}
if (event)
event->set_attr_value(avalue.toStdString());
return avalue;
}
void Server_Card::setCounter(int _id, int value, Event_SetCardCounter *event)
{
if (value)
counters.insert(_id, value);
else
counters.remove(_id);
if (event) {
event->set_counter_id(_id);
event->set_counter_value(value);
}
}
void Server_Card::setParentCard(Server_Card *_parentCard)
{
if (parentCard)
parentCard->removeAttachedCard(this);
parentCard = _parentCard;
if (parentCard)
parentCard->addAttachedCard(this);
}
void Server_Card::getInfo(ServerInfo_Card *info)
{
QString displayedName = facedown ? QString() : cardRef.name;
info->set_id(id);
info->set_provider_id(cardRef.providerId.toStdString());
info->set_name(displayedName.toStdString());
info->set_x(coord_x);
info->set_y(coord_y);
if (facedown) {
info->set_face_down(true);
}
info->set_tapped(tapped);
if (attacking) {
info->set_attacking(true);
}
if (!color.isEmpty()) {
info->set_color(color.toStdString());
}
if (!ptString.isEmpty()) {
info->set_pt(ptString.toStdString());
}
if (!annotation.isEmpty()) {
info->set_annotation(annotation.toStdString());
}
if (destroyOnZoneChange) {
info->set_destroy_on_zone_change(true);
}
if (doesntUntap) {
info->set_doesnt_untap(true);
}
QMapIterator<int, int> cardCounterIterator(counters);
while (cardCounterIterator.hasNext()) {
cardCounterIterator.next();
ServerInfo_CardCounter *counterInfo = info->add_counter_list();
counterInfo->set_id(cardCounterIterator.key());
counterInfo->set_value(cardCounterIterator.value());
}
if (parentCard) {
info->set_attach_player_id(parentCard->getZone()->getPlayer()->getPlayerId());
info->set_attach_zone(parentCard->getZone()->getName().toStdString());
info->set_attach_card_id(parentCard->getId());
}
}

View file

@ -0,0 +1,227 @@
/***************************************************************************
* Copyright (C) 2008 by Max-Wilhelm Bruker *
* brukie@laptop *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef SERVER_CARD_H
#define SERVER_CARD_H
#include "../../card_ref.h"
#include "pb/card_attributes.pb.h"
#include "pb/serverinfo_card.pb.h"
#include "server_arrowtarget.h"
#include <QMap>
#include <QString>
class Server_CardZone;
class Event_SetCardCounter;
class Event_SetCardAttr;
class Server_Card : public Server_ArrowTarget
{
Q_OBJECT
private:
Server_CardZone *zone;
int id;
int coord_x, coord_y;
CardRef cardRef;
QMap<int, int> counters;
bool tapped;
bool attacking;
bool facedown;
QString color;
QString ptString;
QString annotation;
bool destroyOnZoneChange;
bool doesntUntap;
Server_Card *parentCard;
QList<Server_Card *> attachedCards;
Server_Card *stashedCard;
public:
Server_Card(const CardRef &cardRef, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone = nullptr);
~Server_Card() override;
Server_CardZone *getZone() const
{
return zone;
}
void setZone(Server_CardZone *_zone)
{
zone = _zone;
}
int getId() const
{
return id;
}
CardRef getCardRef() const
{
return cardRef;
}
QString getProviderId() const
{
return cardRef.providerId;
}
int getX() const
{
return coord_x;
}
int getY() const
{
return coord_y;
}
QString getName() const
{
return cardRef.name;
}
const QMap<int, int> &getCounters() const
{
return counters;
}
int getCounter(int counter_id) const
{
return counters.value(counter_id, 0);
}
bool getTapped() const
{
return tapped;
}
bool getAttacking() const
{
return attacking;
}
bool getFaceDown() const
{
return facedown;
}
QString getColor() const
{
return color;
}
QString getPT() const
{
return ptString;
}
QString getAnnotation() const
{
return annotation;
}
bool getDoesntUntap() const
{
return doesntUntap;
}
bool getDestroyOnZoneChange() const
{
return destroyOnZoneChange;
}
Server_Card *getParentCard() const
{
return parentCard;
}
const QList<Server_Card *> &getAttachedCards() const
{
return attachedCards;
}
void setId(int _id)
{
id = _id;
}
void setCoords(int x, int y)
{
coord_x = x;
coord_y = y;
}
void setCardRef(const CardRef &_cardRef)
{
cardRef = _cardRef;
}
void setCounter(int _id, int value, Event_SetCardCounter *event = nullptr);
void setTapped(bool _tapped)
{
tapped = _tapped;
}
void setAttacking(bool _attacking)
{
attacking = _attacking;
}
void setFaceDown(bool _facedown)
{
facedown = _facedown;
}
void setColor(const QString &_color)
{
color = _color;
}
void setPT(const QString &_pt)
{
ptString = _pt;
}
void setAnnotation(const QString &_annotation)
{
annotation = _annotation;
}
void setDestroyOnZoneChange(bool _destroy)
{
destroyOnZoneChange = _destroy;
}
void setDoesntUntap(bool _doesntUntap)
{
doesntUntap = _doesntUntap;
}
void setParentCard(Server_Card *_parentCard);
void addAttachedCard(Server_Card *card)
{
attachedCards.append(card);
}
void removeAttachedCard(Server_Card *card)
{
attachedCards.removeOne(card);
}
void setStashedCard(Server_Card *card)
{
// setStashedCard should only be called on creation of a new card, so
// there should never be an already existing stashed card.
Q_ASSERT(!stashedCard);
// Stashed cards can't themselves have stashed cards, and tokens can't
// be stashed.
if (card->stashedCard || card->getDestroyOnZoneChange()) {
stashedCard = card->takeStashedCard();
card->deleteLater();
} else {
stashedCard = card;
}
}
Server_Card *takeStashedCard()
{
Server_Card *oldStashedCard = stashedCard;
stashedCard = nullptr;
return oldStashedCard;
}
void resetState(bool keepAnnotations = false);
QString setAttribute(CardAttribute attribute, const QString &avalue, bool allCards);
QString setAttribute(CardAttribute attribute, const QString &avalue, Event_SetCardAttr *event = nullptr);
void getInfo(ServerInfo_Card *info);
};
#endif

View file

@ -0,0 +1,339 @@
/***************************************************************************
* Copyright (C) 2008 by Max-Wilhelm Bruker *
* brukie@laptop *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "server_cardzone.h"
#include "../rng_abstract.h"
#include "pb/command_move_card.pb.h"
#include "server_card.h"
#include "server_player.h"
#include <QDebug>
#include <QSet>
Server_CardZone::Server_CardZone(Server_Player *_player,
const QString &_name,
bool _has_coords,
ServerInfo_Zone::ZoneType _type)
: player(_player), name(_name), has_coords(_has_coords), type(_type), cardsBeingLookedAt(0),
alwaysRevealTopCard(false), alwaysLookAtTopCard(false)
{
}
Server_CardZone::~Server_CardZone()
{
qDebug() << "Server_CardZone destructor:" << name;
clear();
}
void Server_CardZone::shuffle(int start, int end)
{
cardsBeingLookedAt = 0;
// Size 0 or 1 decks are sorted
if (cards.size() < 2)
return;
// Negative numbers signify positions starting at the end of the
// zone convert these to actual indexes.
if (end < 0)
end += cards.size();
if (start < 0)
start += cards.size();
if (start < 0 || end < 0 || start >= cards.size() || end >= cards.size())
return;
for (int i = end; i > start; i--) {
int j = rng->rand(start, i);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
cards.swapItemsAt(j, i);
#else
cards.swap(j, i);
#endif
}
playersWithWritePermission.clear();
}
void Server_CardZone::removeCardFromCoordMap(Server_Card *card, int oldX, int oldY)
{
if (oldX < 0)
return;
const int baseX = (oldX / 3) * 3;
QMap<int, Server_Card *> &coordMap = coordinateMap[oldY];
if (coordMap.contains(baseX) && coordMap.contains(baseX + 1) && coordMap.contains(baseX + 2))
// If the removal of this card has opened up a previously full pile...
freePilesMap[oldY].insert(coordMap.value(baseX)->getName(), baseX);
coordMap.remove(oldX);
if (!(coordMap.contains(baseX) && coordMap.value(baseX)->getName() == card->getName()) &&
!(coordMap.contains(baseX + 1) && coordMap.value(baseX + 1)->getName() == card->getName()) &&
!(coordMap.contains(baseX + 2) && coordMap.value(baseX + 2)->getName() == card->getName()))
// If this card was the last one with this name...
freePilesMap[oldY].remove(card->getName(), baseX);
if (!coordMap.contains(baseX) && !coordMap.contains(baseX + 1) && !coordMap.contains(baseX + 2)) {
// If the removal of this card has freed a whole pile, i.e. it was the last card in it...
if (baseX < freeSpaceMap[oldY])
freeSpaceMap[oldY] = baseX;
}
}
void Server_CardZone::insertCardIntoCoordMap(Server_Card *card, int x, int y)
{
if (x < 0)
return;
coordinateMap[y].insert(x, card);
if (!(x % 3)) {
if (!card->getFaceDown() && !freePilesMap[y].contains(card->getName(), x) && card->getAttachedCards().isEmpty())
freePilesMap[y].insert(card->getName(), x);
if (freeSpaceMap[y] == x) {
int nextFreeX = x;
do {
nextFreeX += 3;
} while (coordinateMap[y].contains(nextFreeX) || coordinateMap[y].contains(nextFreeX + 1) ||
coordinateMap[y].contains(nextFreeX + 2));
freeSpaceMap[y] = nextFreeX;
}
} else if (!((x - 2) % 3)) {
const int baseX = (x / 3) * 3;
freePilesMap[y].remove(coordinateMap[y].value(baseX)->getName(), baseX);
}
}
int Server_CardZone::removeCard(Server_Card *card)
{
bool wasLookedAt;
return removeCard(card, wasLookedAt);
}
int Server_CardZone::removeCard(Server_Card *card, bool &wasLookedAt)
{
int index = cards.indexOf(card);
wasLookedAt = isCardAtPosLookedAt(index);
if (wasLookedAt && cardsBeingLookedAt > 0) {
cardsBeingLookedAt -= 1;
}
cards.removeAt(index);
if (has_coords) {
removeCardFromCoordMap(card, card->getX(), card->getY());
}
card->setZone(nullptr);
return index;
}
Server_Card *Server_CardZone::getCard(int id, int *position, bool remove)
{
if (type != ServerInfo_Zone::HiddenZone) {
for (int i = 0; i < cards.size(); ++i) {
Server_Card *tmp = cards[i];
if (tmp->getId() == id) {
if (position)
*position = i;
if (remove) {
cards.removeAt(i);
tmp->setZone(nullptr);
}
return tmp;
}
}
return nullptr;
} else {
if ((id >= cards.size()) || (id < 0))
return nullptr;
Server_Card *tmp = cards[id];
if (position)
*position = id;
if (remove) {
cards.removeAt(id);
tmp->setZone(nullptr);
}
return tmp;
}
}
bool Server_CardZone::isCardAtPosLookedAt(int pos) const
{
return type == ServerInfo_Zone::HiddenZone && (cardsBeingLookedAt == -1 || cardsBeingLookedAt > pos);
}
int Server_CardZone::getFreeGridColumn(int x, int y, const QString &cardName, bool dontStackSameName) const
{
const QMap<int, Server_Card *> &coordMap = coordinateMap.value(y);
if (x == -1) {
if (!dontStackSameName && freePilesMap[y].contains(cardName)) {
x = (freePilesMap[y].value(cardName) / 3) * 3;
if (coordMap.contains(x) && (coordMap[x]->getFaceDown() || !coordMap[x]->getAttachedCards().isEmpty())) {
// don't pile up on: 1. facedown cards 2. cards with attached cards
} else if (!coordMap.contains(x))
return x;
else if (!coordMap.contains(x + 1))
return x + 1;
else
return x + 2;
}
} else if (x >= 0) {
int resultX = 0;
x = (x / 3) * 3;
if (!coordMap.contains(x))
resultX = x;
else if (!coordMap.value(x)->getAttachedCards().isEmpty()) {
resultX = x;
x = -1;
} else if (!coordMap.contains(x + 1))
resultX = x + 1;
else if (!coordMap.contains(x + 2))
resultX = x + 2;
else {
resultX = x;
x = -1;
}
if (x < 0)
while (coordMap.contains(resultX))
resultX += 3;
return resultX;
}
return freeSpaceMap[y];
}
bool Server_CardZone::isColumnStacked(int x, int y) const
{
if (!has_coords)
return false;
return coordinateMap[y].contains((x / 3) * 3 + 1);
}
bool Server_CardZone::isColumnEmpty(int x, int y) const
{
if (!has_coords)
return true;
return !coordinateMap[y].contains((x / 3) * 3);
}
void Server_CardZone::moveCardInRow(GameEventStorage &ges, Server_Card *card, int x, int y)
{
auto *cardToMove = new CardToMove;
cardToMove->set_card_id(card->getId());
player->moveCard(ges, this, QList<const CardToMove *>() << cardToMove, this, x, y, false, false);
delete cardToMove;
}
void Server_CardZone::fixFreeSpaces(GameEventStorage &ges)
{
if (!has_coords)
return;
QSet<QPair<int, int>> placesToLook;
for (auto &card : cards)
placesToLook.insert(QPair<int, int>((card->getX() / 3) * 3, card->getY()));
QSetIterator<QPair<int, int>> placeIterator(placesToLook);
while (placeIterator.hasNext()) {
const QPair<int, int> &foo = placeIterator.next();
int baseX = foo.first;
int y = foo.second;
if (!coordinateMap[y].contains(baseX)) {
if (coordinateMap[y].contains(baseX + 1))
moveCardInRow(ges, coordinateMap[y].value(baseX + 1), baseX, y);
else if (coordinateMap[y].contains(baseX + 2)) {
moveCardInRow(ges, coordinateMap[y].value(baseX + 2), baseX, y);
continue;
} else
continue;
}
if (!coordinateMap[y].contains(baseX + 1) && coordinateMap[y].contains(baseX + 2))
moveCardInRow(ges, coordinateMap[y].value(baseX + 2), baseX + 1, y);
}
}
void Server_CardZone::updateCardCoordinates(Server_Card *card, int oldX, int oldY)
{
if (!has_coords)
return;
if (oldX != -1)
removeCardFromCoordMap(card, oldX, oldY);
insertCardIntoCoordMap(card, card->getX(), card->getY());
}
void Server_CardZone::insertCard(Server_Card *card, int x, int y)
{
if (hasCoords()) {
card->setCoords(x, y);
cards.append(card);
insertCardIntoCoordMap(card, x, y);
} else {
card->setCoords(0, 0);
if (0 <= x && x < cards.length()) {
cards.insert(x, card);
} else {
cards.append(card);
}
}
card->setZone(this);
}
void Server_CardZone::clear()
{
for (auto card : cards)
delete card;
cards.clear();
coordinateMap.clear();
freePilesMap.clear();
freeSpaceMap.clear();
playersWithWritePermission.clear();
cardsBeingLookedAt = 0;
}
void Server_CardZone::addWritePermission(int playerId)
{
playersWithWritePermission.insert(playerId);
}
void Server_CardZone::getInfo(ServerInfo_Zone *info, Server_AbstractParticipant *recipient, bool omniscient)
{
info->set_name(name.toStdString());
info->set_type(type);
info->set_with_coords(has_coords);
info->set_card_count(static_cast<int>(cards.size()));
info->set_always_reveal_top_card(alwaysRevealTopCard);
info->set_always_look_at_top_card(alwaysLookAtTopCard);
const bool selfPlayerAsking = recipient == player || omniscient;
const bool zonesSelfCanSee = type != ServerInfo_Zone::HiddenZone;
const bool otherPlayerAsking = recipient != player;
const bool zonesOthersCanSee = type == ServerInfo_Zone::PublicZone;
if ((selfPlayerAsking && zonesSelfCanSee) || (otherPlayerAsking && zonesOthersCanSee)) {
QListIterator<Server_Card *> cardIterator(cards);
while (cardIterator.hasNext())
cardIterator.next()->getInfo(info->add_card_list());
}
}

View file

@ -0,0 +1,125 @@
/***************************************************************************
* Copyright (C) 2008 by Max-Wilhelm Bruker *
* brukie@laptop *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef SERVER_CARDZONE_H
#define SERVER_CARDZONE_H
#include "pb/serverinfo_zone.pb.h"
#include <QList>
#include <QMap>
#include <QSet>
#include <QString>
class Server_Card;
class Server_Player;
class Server_AbstractParticipant;
class Server_Game;
class GameEventStorage;
class Server_CardZone
{
private:
Server_Player *player;
QString name;
bool has_coords; // having coords means this zone has x and y coordinates
ServerInfo_Zone::ZoneType type;
int cardsBeingLookedAt;
QSet<int> playersWithWritePermission;
bool alwaysRevealTopCard;
bool alwaysLookAtTopCard;
QList<Server_Card *> cards;
QMap<int, QMap<int, Server_Card *>> coordinateMap; // y -> (x -> card)
QMap<int, QMultiMap<QString, int>> freePilesMap; // y -> (cardName -> x)
QMap<int, int> freeSpaceMap; // y -> x
void removeCardFromCoordMap(Server_Card *card, int oldX, int oldY);
void insertCardIntoCoordMap(Server_Card *card, int x, int y);
public:
Server_CardZone(Server_Player *_player, const QString &_name, bool _has_coords, ServerInfo_Zone::ZoneType _type);
~Server_CardZone();
const QList<Server_Card *> &getCards() const
{
return cards;
}
int removeCard(Server_Card *card);
int removeCard(Server_Card *card, bool &wasLookedAt);
Server_Card *getCard(int id, int *position = nullptr, bool remove = false);
int getCardsBeingLookedAt() const
{
return cardsBeingLookedAt;
}
void setCardsBeingLookedAt(int _cardsBeingLookedAt)
{
cardsBeingLookedAt = qMax(0, _cardsBeingLookedAt);
}
bool isCardAtPosLookedAt(int pos) const;
bool hasCoords() const
{
return has_coords;
}
ServerInfo_Zone::ZoneType getType() const
{
return type;
}
QString getName() const
{
return name;
}
Server_Player *getPlayer() const
{
return player;
}
void getInfo(ServerInfo_Zone *info, Server_AbstractParticipant *recipient, bool omniscient);
int getFreeGridColumn(int x, int y, const QString &cardName, bool dontStackSameName) const;
bool isColumnEmpty(int x, int y) const;
bool isColumnStacked(int x, int y) const;
void fixFreeSpaces(GameEventStorage &ges);
void moveCardInRow(GameEventStorage &ges, Server_Card *card, int x, int y);
void insertCard(Server_Card *card, int x, int y);
void updateCardCoordinates(Server_Card *card, int oldX, int oldY);
void shuffle(int start = 0, int end = -1);
void clear();
void addWritePermission(int playerId);
const QSet<int> &getPlayersWithWritePermission() const
{
return playersWithWritePermission;
}
bool getAlwaysRevealTopCard() const
{
return alwaysRevealTopCard;
}
void setAlwaysRevealTopCard(bool _alwaysRevealTopCard)
{
alwaysRevealTopCard = _alwaysRevealTopCard;
}
bool getAlwaysLookAtTopCard() const
{
return alwaysLookAtTopCard;
}
void setAlwaysLookAtTopCard(bool _alwaysLookAtTopCard)
{
alwaysLookAtTopCard = _alwaysLookAtTopCard;
}
};
#endif

View file

@ -0,0 +1,17 @@
#include "server_counter.h"
#include "pb/serverinfo_counter.pb.h"
Server_Counter::Server_Counter(int _id, const QString &_name, const color &_counterColor, int _radius, int _count)
: id(_id), name(_name), counterColor(_counterColor), radius(_radius), count(_count)
{
}
void Server_Counter::getInfo(ServerInfo_Counter *info)
{
info->set_id(id);
info->set_name(name.toStdString());
info->mutable_counter_color()->CopyFrom(counterColor);
info->set_radius(radius);
info->set_count(count);
}

View file

@ -0,0 +1,71 @@
/***************************************************************************
* Copyright (C) 2008 by Max-Wilhelm Bruker *
* brukie@laptop *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef SERVER_COUNTER_H
#define SERVER_COUNTER_H
#include "pb/color.pb.h"
#include <QString>
class ServerInfo_Counter;
class Server_Counter
{
protected:
int id;
QString name;
color counterColor;
int radius;
int count;
public:
Server_Counter(int _id, const QString &_name, const color &_counterColor, int _radius, int _count = 0);
~Server_Counter()
{
}
int getId() const
{
return id;
}
QString getName() const
{
return name;
}
const color &getColor() const
{
return counterColor;
}
int getRadius() const
{
return radius;
}
int getCount() const
{
return count;
}
void setCount(int _count)
{
count = _count;
}
void getInfo(ServerInfo_Counter *info);
};
#endif

View file

@ -0,0 +1,825 @@
/***************************************************************************
* Copyright (C) 2008 by Max-Wilhelm Bruker *
* brukie@laptop *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "server_game.h"
#include "../../deck_list.h"
#include "../server.h"
#include "../server_database_interface.h"
#include "../server_protocolhandler.h"
#include "../server_room.h"
#include "pb/context_connection_state_changed.pb.h"
#include "pb/context_deck_select.pb.h"
#include "pb/context_ping_changed.pb.h"
#include "pb/event_delete_arrow.pb.h"
#include "pb/event_game_closed.pb.h"
#include "pb/event_game_host_changed.pb.h"
#include "pb/event_game_joined.pb.h"
#include "pb/event_game_state_changed.pb.h"
#include "pb/event_join.pb.h"
#include "pb/event_kicked.pb.h"
#include "pb/event_leave.pb.h"
#include "pb/event_player_properties_changed.pb.h"
#include "pb/event_replay_added.pb.h"
#include "pb/event_set_active_phase.pb.h"
#include "pb/event_set_active_player.pb.h"
#include "pb/game_replay.pb.h"
#include "pb/serverinfo_playerping.pb.h"
#include "server_arrow.h"
#include "server_card.h"
#include "server_cardzone.h"
#include "server_player.h"
#include "server_spectator.h"
#include <QDebug>
#include <QTimer>
#include <google/protobuf/descriptor.h>
Server_Game::Server_Game(const ServerInfo_User &_creatorInfo,
int _gameId,
const QString &_description,
const QString &_password,
int _maxPlayers,
const QList<int> &_gameTypes,
bool _onlyBuddies,
bool _onlyRegistered,
bool _spectatorsAllowed,
bool _spectatorsNeedPassword,
bool _spectatorsCanTalk,
bool _spectatorsSeeEverything,
int _startingLifeTotal,
bool _shareDecklistsOnLoad,
Server_Room *_room)
: QObject(), room(_room), nextPlayerId(0), hostId(0), creatorInfo(new ServerInfo_User(_creatorInfo)),
gameStarted(false), gameClosed(false), gameId(_gameId), password(_password), maxPlayers(_maxPlayers),
gameTypes(_gameTypes), activePlayer(-1), activePhase(-1), onlyBuddies(_onlyBuddies),
onlyRegistered(_onlyRegistered), spectatorsAllowed(_spectatorsAllowed),
spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk),
spectatorsSeeEverything(_spectatorsSeeEverything), startingLifeTotal(_startingLifeTotal),
shareDecklistsOnLoad(_shareDecklistsOnLoad), inactivityCounter(0), startTimeOfThisGame(0), secondsElapsed(0),
firstGameStarted(false), turnOrderReversed(false), startTime(QDateTime::currentDateTime()), pingClock(nullptr),
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
gameMutex()
#else
gameMutex(QMutex::Recursive)
#endif
{
currentReplay = new GameReplay;
currentReplay->set_replay_id(room->getServer()->getDatabaseInterface()->getNextReplayId());
description = _description.simplified();
connect(this, &Server_Game::sigStartGameIfReady, this, &Server_Game::doStartGameIfReady, Qt::QueuedConnection);
getInfo(*currentReplay->mutable_game_info());
if (room->getServer()->getGameShouldPing()) {
pingClock = new QTimer(this);
connect(pingClock, &QTimer::timeout, this, &Server_Game::pingClockTimeout);
pingClock->start(1000);
}
}
Server_Game::~Server_Game()
{
room->gamesLock.lockForWrite();
gameMutex.lock();
gameClosed = true;
sendGameEventContainer(prepareGameEvent(Event_GameClosed(), -1));
for (auto *participant : participants.values()) {
participant->prepareDestroy();
}
participants.clear();
room->removeGame(this);
delete creatorInfo;
creatorInfo = 0;
gameMutex.unlock();
room->gamesLock.unlock();
currentReplay->set_duration_seconds(secondsElapsed - startTimeOfThisGame);
replayList.append(currentReplay);
storeGameInformation();
for (auto *replay : replayList) {
delete replay;
}
replayList.clear();
room = nullptr;
currentReplay = nullptr;
creatorInfo = nullptr;
if (pingClock) {
delete pingClock;
pingClock = nullptr;
}
qDebug() << "Server_Game destructor: gameId=" << gameId;
deleteLater();
}
void Server_Game::storeGameInformation()
{
const ServerInfo_Game &gameInfo = replayList.first()->game_info();
Event_ReplayAdded replayEvent;
ServerInfo_ReplayMatch *replayMatchInfo = replayEvent.mutable_match_info();
replayMatchInfo->set_game_id(gameInfo.game_id());
replayMatchInfo->set_room_name(room->getName().toStdString());
replayMatchInfo->set_time_started(QDateTime::currentDateTime().addSecs(-secondsElapsed).toSecsSinceEpoch());
replayMatchInfo->set_length(secondsElapsed);
replayMatchInfo->set_game_name(gameInfo.description());
const QStringList &allGameTypes = room->getGameTypes();
QStringList _gameTypes;
for (int i = gameInfo.game_types_size() - 1; i >= 0; --i)
_gameTypes.append(allGameTypes[gameInfo.game_types(i)]);
for (const auto &playerName : allPlayersEver) {
replayMatchInfo->add_player_names(playerName.toStdString());
}
for (int i = 0; i < replayList.size(); ++i) {
ServerInfo_Replay *replayInfo = replayMatchInfo->add_replay_list();
replayInfo->set_replay_id(replayList[i]->replay_id());
replayInfo->set_replay_name(gameInfo.description());
replayInfo->set_duration(replayList[i]->duration_seconds());
}
SessionEvent *sessionEvent = Server_ProtocolHandler::prepareSessionEvent(replayEvent);
Server *server = room->getServer();
server->clientsLock.lockForRead();
for (auto userName : allPlayersEver + allSpectatorsEver) {
Server_AbstractUserInterface *userHandler = server->findUser(userName);
if (userHandler && server->getStoreReplaysEnabled())
userHandler->sendProtocolItem(*sessionEvent);
}
server->clientsLock.unlock();
delete sessionEvent;
if (server->getStoreReplaysEnabled()) {
server->getDatabaseInterface()->storeGameInformation(room->getName(), _gameTypes, gameInfo, allPlayersEver,
allSpectatorsEver, replayList);
}
}
void Server_Game::pingClockTimeout()
{
QMutexLocker locker(&gameMutex);
++secondsElapsed;
GameEventStorage ges;
ges.setGameEventContext(Context_PingChanged());
bool allPlayersInactive = true;
int playerCount = 0;
for (auto *participant : participants) {
if (participant == nullptr)
continue;
if (!participant->getSpectator()) {
++playerCount;
}
if (participant->updatePingTime()) {
Event_PlayerPropertiesChanged event;
event.mutable_player_properties()->set_ping_seconds(participant->getPingTime());
ges.enqueueGameEvent(event, participant->getPlayerId());
}
if ((participant->getPingTime() != -1) &&
(!participant->getSpectator() || participant->getPlayerId() == hostId)) {
allPlayersInactive = false;
}
}
ges.sendToGame(this);
const int maxTime = room->getServer()->getMaxGameInactivityTime();
if (allPlayersInactive) {
if (((maxTime > 0) && (++inactivityCounter >= maxTime)) || (playerCount < maxPlayers)) {
deleteLater();
}
} else {
inactivityCounter = 0;
}
}
QMap<int, Server_Player *> Server_Game::getPlayers() const // copies pointers to new map
{
QMap<int, Server_Player *> players;
QMutexLocker locker(&gameMutex);
for (int id : participants.keys()) {
auto *participant = participants[id];
if (!participant->getSpectator()) {
players[id] = static_cast<Server_Player *>(participant);
}
}
return players;
}
Server_Player *Server_Game::getPlayer(int id) const
{
auto *participant = participants.value(id);
if (!participant->getSpectator()) {
return static_cast<Server_Player *>(participant);
} else {
return nullptr;
}
}
int Server_Game::getPlayerCount() const
{
return participants.size() - getSpectatorCount();
}
int Server_Game::getSpectatorCount() const
{
QMutexLocker locker(&gameMutex);
int result = 0;
for (Server_AbstractParticipant *participant : participants.values()) {
if (participant->getSpectator())
++result;
}
return result;
}
void Server_Game::createGameStateChangedEvent(Event_GameStateChanged *event,
Server_AbstractParticipant *recipient,
bool omniscient,
bool withUserInfo)
{
event->set_seconds_elapsed(secondsElapsed);
if (gameStarted) {
event->set_game_started(true);
event->set_active_player_id(0);
event->set_active_phase(0);
} else
event->set_game_started(false);
for (Server_AbstractParticipant *participant : participants.values()) {
participant->getInfo(event->add_player_list(), recipient, omniscient, withUserInfo);
}
}
void Server_Game::sendGameStateToPlayers()
{
// game state information for replay and omniscient spectators
Event_GameStateChanged omniscientEvent;
createGameStateChangedEvent(&omniscientEvent, nullptr, true, false);
GameEventContainer *replayCont = prepareGameEvent(omniscientEvent, -1);
replayCont->set_seconds_elapsed(secondsElapsed - startTimeOfThisGame);
replayCont->clear_game_id();
currentReplay->add_event_list()->CopyFrom(*replayCont);
delete replayCont;
// If spectators are not omniscient, we need an additional createGameStateChangedEvent call, otherwise we can use
// the data we used for the replay. All spectators are equal, so we don't need to make a createGameStateChangedEvent
// call for each one.
Event_GameStateChanged spectatorNormalEvent;
createGameStateChangedEvent(&spectatorNormalEvent, nullptr, false, false);
// send game state info to clients according to their role in the game
for (auto *participant : participants.values()) {
GameEventContainer *gec;
if (participant->getSpectator()) {
if (spectatorsSeeEverything || participant->getJudge()) {
gec = prepareGameEvent(omniscientEvent, -1);
} else {
gec = prepareGameEvent(spectatorNormalEvent, -1);
}
} else {
Event_GameStateChanged event;
createGameStateChangedEvent(&event, participant, false, false);
gec = prepareGameEvent(event, -1);
}
participant->sendGameEvent(*gec);
delete gec;
}
}
void Server_Game::doStartGameIfReady(bool forceStartGame)
{
Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface();
QMutexLocker locker(&gameMutex);
if (getPlayerCount() < maxPlayers && !forceStartGame) {
return;
}
auto players = getPlayers();
for (auto *player : players.values()) {
if (!player->getReadyStart()) {
if (forceStartGame) {
// Player is not ready to start, so kick them
// TODO: Move them to Spectators instead
kickParticipant(player->getPlayerId());
} else {
return;
}
}
}
for (Server_Player *player : players.values()) {
player->setupZones();
}
gameStarted = true;
for (auto *player : players.values()) {
player->setConceded(false);
player->setReadyStart(false);
}
if (firstGameStarted) {
currentReplay->set_duration_seconds(secondsElapsed - startTimeOfThisGame);
replayList.append(currentReplay);
currentReplay = new GameReplay;
currentReplay->set_replay_id(databaseInterface->getNextReplayId());
ServerInfo_Game *gameInfo = currentReplay->mutable_game_info();
getInfo(*gameInfo);
gameInfo->set_started(false);
Event_GameStateChanged omniscientEvent;
createGameStateChangedEvent(&omniscientEvent, nullptr, true, true);
GameEventContainer *replayCont = prepareGameEvent(omniscientEvent, -1);
replayCont->set_seconds_elapsed(0);
replayCont->clear_game_id();
currentReplay->add_event_list()->CopyFrom(*replayCont);
delete replayCont;
startTimeOfThisGame = secondsElapsed;
} else
firstGameStarted = true;
sendGameStateToPlayers();
activePlayer = -1;
nextTurn();
locker.unlock();
ServerInfo_Game gameInfo;
gameInfo.set_room_id(room->getId());
gameInfo.set_game_id(gameId);
gameInfo.set_started(true);
emit gameInfoChanged(gameInfo);
}
void Server_Game::startGameIfReady(bool forceStartGame)
{
emit sigStartGameIfReady(forceStartGame);
}
void Server_Game::stopGameIfFinished()
{
QMutexLocker locker(&gameMutex);
int playing = 0;
auto players = getPlayers();
for (auto *player : players.values()) {
if (!player->getConceded())
++playing;
}
if (playing > 1)
return;
gameStarted = false;
for (auto *player : players.values()) {
player->clearZones();
player->setConceded(false);
}
sendGameStateToPlayers();
locker.unlock();
ServerInfo_Game gameInfo;
gameInfo.set_room_id(room->getId());
gameInfo.set_game_id(gameId);
gameInfo.set_started(false);
emit gameInfoChanged(gameInfo);
}
Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user,
const QString &_password,
bool spectator,
bool overrideRestrictions,
bool asJudge)
{
Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface();
for (auto *participant : participants.values()) {
if (participant->getUserInfo()->name() == user->name())
return Response::RespContextError;
}
if (asJudge && !(user->user_level() & ServerInfo_User::IsJudge)) {
return Response::RespUserLevelTooLow;
}
if (!(overrideRestrictions && (user->user_level() & ServerInfo_User::IsModerator))) {
if ((_password != password) && !(spectator && !spectatorsNeedPassword))
return Response::RespWrongPassword;
if (!(user->user_level() & ServerInfo_User::IsRegistered) && onlyRegistered)
return Response::RespUserLevelTooLow;
if (onlyBuddies && (user->name() != creatorInfo->name()))
if (!databaseInterface->isInBuddyList(QString::fromStdString(creatorInfo->name()),
QString::fromStdString(user->name())))
return Response::RespOnlyBuddies;
if (databaseInterface->isInIgnoreList(QString::fromStdString(creatorInfo->name()),
QString::fromStdString(user->name())))
return Response::RespInIgnoreList;
if (spectator) {
if (!spectatorsAllowed)
return Response::RespSpectatorsNotAllowed;
}
}
if (!spectator && (gameStarted || (getPlayerCount() >= getMaxPlayers())))
return Response::RespGameFull;
return Response::RespOk;
}
bool Server_Game::containsUser(const QString &userName) const
{
QMutexLocker locker(&gameMutex);
for (auto *participant : participants.values()) {
if (participant->getUserInfo()->name() == userName.toStdString())
return true;
}
return false;
}
void Server_Game::addPlayer(Server_AbstractUserInterface *userInterface,
ResponseContainer &rc,
bool spectator,
bool judge,
bool broadcastUpdate)
{
QMutexLocker locker(&gameMutex);
Server_AbstractParticipant *newParticipant;
if (spectator) {
newParticipant = new Server_Spectator(this, nextPlayerId++, userInterface->copyUserInfo(true, true, true),
judge, userInterface);
} else {
newParticipant = new Server_Player(this, nextPlayerId++, userInterface->copyUserInfo(true, true, true), judge,
userInterface);
}
newParticipant->moveToThread(thread());
Event_Join joinEvent;
newParticipant->getProperties(*joinEvent.mutable_player_properties(), true);
sendGameEventContainer(prepareGameEvent(joinEvent, -1));
const QString playerName = QString::fromStdString(newParticipant->getUserInfo()->name());
participants.insert(newParticipant->getPlayerId(), newParticipant);
if (spectator) {
allSpectatorsEver.insert(playerName);
} else {
allPlayersEver.insert(playerName);
// if the original creator of the game joins, give them host status back
// FIXME: transferring host to spectators has side effects
if (newParticipant->getUserInfo()->name() == creatorInfo->name()) {
hostId = newParticipant->getPlayerId();
sendGameEventContainer(prepareGameEvent(Event_GameHostChanged(), hostId));
}
}
if (broadcastUpdate) {
ServerInfo_Game gameInfo;
gameInfo.set_room_id(room->getId());
gameInfo.set_game_id(gameId);
gameInfo.set_player_count(getPlayerCount());
gameInfo.set_spectators_count(getSpectatorCount());
emit gameInfoChanged(gameInfo);
}
if ((newParticipant->getUserInfo()->user_level() & ServerInfo_User::IsRegistered) && !spectator)
room->getServer()->addPersistentPlayer(playerName, room->getId(), gameId, newParticipant->getPlayerId());
userInterface->playerAddedToGame(gameId, room->getId(), newParticipant->getPlayerId());
createGameJoinedEvent(newParticipant, rc, false);
}
void Server_Game::removeParticipant(Server_AbstractParticipant *participant, Event_Leave::LeaveReason reason)
{
room->getServer()->removePersistentPlayer(QString::fromStdString(participant->getUserInfo()->name()), room->getId(),
gameId, participant->getPlayerId());
participants.remove(participant->getPlayerId());
bool spectator = participant->getSpectator();
GameEventStorage ges;
if (!spectator) {
auto *player = static_cast<Server_Player *>(participant);
removeArrowsRelatedToPlayer(ges, player);
unattachCards(ges, player);
}
Event_Leave event;
event.set_reason(reason);
ges.enqueueGameEvent(event, participant->getPlayerId());
ges.sendToGame(this);
bool playerActive = activePlayer == participant->getPlayerId();
bool playerHost = hostId == participant->getPlayerId();
participant->prepareDestroy();
if (playerHost) {
int newHostId = -1;
for (auto *otherPlayer : getPlayers().values()) {
newHostId = otherPlayer->getPlayerId();
break;
}
if (newHostId != -1) {
hostId = newHostId;
sendGameEventContainer(prepareGameEvent(Event_GameHostChanged(), hostId));
} else {
gameClosed = true;
deleteLater();
return;
}
}
if (!spectator) {
stopGameIfFinished();
if (gameStarted && playerActive)
nextTurn();
}
ServerInfo_Game gameInfo;
gameInfo.set_room_id(room->getId());
gameInfo.set_game_id(gameId);
gameInfo.set_player_count(getPlayerCount());
gameInfo.set_spectators_count(getSpectatorCount());
emit gameInfoChanged(gameInfo);
}
void Server_Game::removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Player *player)
{
QMutexLocker locker(&gameMutex);
// Remove all arrows of other players pointing to the player being removed or to one of his cards.
// Also remove all arrows starting at one of his cards. This is necessary since players can create
// arrows that start at another person's cards.
for (Server_Player *anyPlayer : getPlayers().values()) {
QList<Server_Arrow *> arrows = anyPlayer->getArrows().values();
QList<Server_Arrow *> toDelete;
for (int i = 0; i < arrows.size(); ++i) {
Server_Arrow *arrow = arrows[i];
Server_Card *targetCard = qobject_cast<Server_Card *>(arrow->getTargetItem());
if (targetCard) {
if (targetCard->getZone() != nullptr && targetCard->getZone()->getPlayer() == player)
toDelete.append(arrow);
} else if (static_cast<Server_Player *>(arrow->getTargetItem()) == player)
toDelete.append(arrow);
// Don't use else here! It has to happen regardless of whether targetCard == 0.
if (arrow->getStartCard()->getZone() != nullptr && arrow->getStartCard()->getZone()->getPlayer() == player)
toDelete.append(arrow);
}
for (int i = 0; i < toDelete.size(); ++i) {
Event_DeleteArrow event;
event.set_arrow_id(toDelete[i]->getId());
ges.enqueueGameEvent(event, player->getPlayerId());
player->deleteArrow(toDelete[i]->getId());
}
}
}
void Server_Game::unattachCards(GameEventStorage &ges, Server_Player *player)
{
QMutexLocker locker(&gameMutex);
for (auto zone : player->getZones()) {
for (auto card : zone->getCards()) {
// Make a copy of the list because the original one gets modified during the loop
QList<Server_Card *> attachedCards = card->getAttachedCards();
for (Server_Card *attachedCard : attachedCards) {
auto otherPlayer = attachedCard->getZone()->getPlayer();
// do not modify the current player's zone!
// this would cause the current card iterator to be invalidated!
// we only have to return cards owned by other players
// because the current player is leaving the game anyway
if (otherPlayer != player) {
otherPlayer->unattachCard(ges, attachedCard);
}
}
}
}
}
bool Server_Game::kickParticipant(int playerId)
{
QMutexLocker locker(&gameMutex);
auto *participant = participants.value(playerId);
if (!participant)
return false;
GameEventContainer *gec = prepareGameEvent(Event_Kicked(), -1);
participant->sendGameEvent(*gec);
delete gec;
removeParticipant(participant, Event_Leave::USER_KICKED);
return true;
}
void Server_Game::setActivePlayer(int _activePlayer)
{
QMutexLocker locker(&gameMutex);
activePlayer = _activePlayer;
Event_SetActivePlayer event;
event.set_active_player_id(activePlayer);
sendGameEventContainer(prepareGameEvent(event, -1));
setActivePhase(0);
}
void Server_Game::setActivePhase(int _activePhase)
{
QMutexLocker locker(&gameMutex);
for (auto *player : getPlayers().values()) {
QList<Server_Arrow *> toDelete = player->getArrows().values();
for (int i = 0; i < toDelete.size(); ++i) {
Server_Arrow *a = toDelete[i];
Event_DeleteArrow event;
event.set_arrow_id(a->getId());
sendGameEventContainer(prepareGameEvent(event, player->getPlayerId()));
player->deleteArrow(a->getId());
}
}
activePhase = _activePhase;
Event_SetActivePhase event;
event.set_phase(activePhase);
sendGameEventContainer(prepareGameEvent(event, -1));
}
void Server_Game::nextTurn()
{
QMutexLocker locker(&gameMutex);
if (participants.isEmpty()) {
qWarning() << "Server_Game::nextTurn was called while players is empty; gameId = " << gameId;
return;
}
auto players = getPlayers();
const QList<int> keys = players.keys();
int listPos = -1;
if (activePlayer != -1) {
listPos = keys.indexOf(activePlayer);
}
do {
if (turnOrderReversed) {
--listPos;
if (listPos < 0) {
listPos = keys.size() - 1;
}
} else {
++listPos;
if (listPos == keys.size()) {
listPos = 0;
}
}
} while (players.value(keys[listPos])->getConceded());
setActivePlayer(keys[listPos]);
}
void Server_Game::createGameJoinedEvent(Server_AbstractParticipant *joiningParticipant,
ResponseContainer &rc,
bool resuming)
{
Event_GameJoined event1;
getInfo(*event1.mutable_game_info());
event1.set_host_id(hostId);
event1.set_player_id(joiningParticipant->getPlayerId());
event1.set_spectator(joiningParticipant->getSpectator());
event1.set_judge(joiningParticipant->getJudge());
event1.set_resuming(resuming);
if (resuming) {
const QStringList &allGameTypes = room->getGameTypes();
for (int i = 0; i < allGameTypes.size(); ++i) {
ServerInfo_GameType *newGameType = event1.add_game_types();
newGameType->set_game_type_id(i);
newGameType->set_description(allGameTypes[i].toStdString());
}
}
rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, Server_AbstractUserInterface::prepareSessionEvent(event1));
Event_GameStateChanged event2;
event2.set_seconds_elapsed(secondsElapsed);
event2.set_game_started(gameStarted);
event2.set_active_player_id(activePlayer);
event2.set_active_phase(activePhase);
bool omniscient = joiningParticipant->getSpectator() && (spectatorsSeeEverything || joiningParticipant->getJudge());
for (auto *participant : participants.values()) {
participant->getInfo(event2.add_player_list(), joiningParticipant, omniscient, true);
}
rc.enqueuePostResponseItem(ServerMessage::GAME_EVENT_CONTAINER, prepareGameEvent(event2, -1));
}
void Server_Game::sendGameEventContainer(GameEventContainer *cont,
GameEventStorageItem::EventRecipients recipients,
int privatePlayerId)
{
QMutexLocker locker(&gameMutex);
cont->set_game_id(gameId);
for (auto *participant : participants.values()) {
const bool playerPrivate =
(participant->getPlayerId() == privatePlayerId) ||
(participant->getSpectator() && (spectatorsSeeEverything || participant->getJudge()));
if ((recipients.testFlag(GameEventStorageItem::SendToPrivate) && playerPrivate) ||
(recipients.testFlag(GameEventStorageItem::SendToOthers) && !playerPrivate))
participant->sendGameEvent(*cont);
}
if (recipients.testFlag(GameEventStorageItem::SendToPrivate)) {
cont->set_seconds_elapsed(secondsElapsed - startTimeOfThisGame);
cont->clear_game_id();
currentReplay->add_event_list()->CopyFrom(*cont);
}
delete cont;
}
GameEventContainer *
Server_Game::prepareGameEvent(const ::google::protobuf::Message &gameEvent, int playerId, GameEventContext *context)
{
GameEventContainer *cont = new GameEventContainer;
cont->set_game_id(gameId);
if (context)
cont->mutable_context()->CopyFrom(*context);
GameEvent *event = cont->add_event_list();
if (playerId != -1)
event->set_player_id(playerId);
event->GetReflection()
->MutableMessage(event, gameEvent.GetDescriptor()->FindExtensionByName("ext"))
->CopyFrom(gameEvent);
return cont;
}
void Server_Game::getInfo(ServerInfo_Game &result) const
{
QMutexLocker locker(&gameMutex);
result.set_room_id(room->getId());
result.set_game_id(gameId);
if (gameClosed) {
result.set_closed(true);
} else {
for (auto type : gameTypes) {
result.add_game_types(type);
}
result.set_max_players(getMaxPlayers());
result.set_description(getDescription().toStdString());
result.set_with_password(!getPassword().isEmpty());
result.set_player_count(getPlayerCount());
result.set_started(gameStarted);
result.mutable_creator_info()->CopyFrom(*getCreatorInfo());
result.set_only_buddies(onlyBuddies);
result.set_only_registered(onlyRegistered);
result.set_spectators_allowed(getSpectatorsAllowed());
result.set_spectators_need_password(getSpectatorsNeedPassword());
result.set_spectators_can_chat(spectatorsCanTalk);
result.set_spectators_omniscient(spectatorsSeeEverything);
result.set_share_decklists_on_load(shareDecklistsOnLoad);
result.set_spectators_count(getSpectatorCount());
result.set_start_time(startTime.toSecsSinceEpoch());
}
}

View file

@ -0,0 +1,226 @@
/***************************************************************************
* Copyright (C) 2008 by Max-Wilhelm Bruker *
* brukie@laptop *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef SERVERGAME_H
#define SERVERGAME_H
#include "../server_response_containers.h"
#include "pb/event_leave.pb.h"
#include "pb/response.pb.h"
#include "pb/serverinfo_game.pb.h"
#include <QDateTime>
#include <QMap>
#include <QMutex>
#include <QObject>
#include <QSet>
#include <QStringList>
class QTimer;
class GameEventContainer;
class GameReplay;
class Server_Room;
class Server_Player;
class Server_AbstractParticipant;
class ServerInfo_User;
class ServerInfo_Game;
class Server_AbstractUserInterface;
class Event_GameStateChanged;
class Server_Game : public QObject
{
Q_OBJECT
private:
Server_Room *room;
int nextPlayerId;
int hostId;
ServerInfo_User *creatorInfo;
QMap<int, Server_AbstractParticipant *> participants;
QSet<QString> allPlayersEver, allSpectatorsEver;
bool gameStarted;
bool gameClosed;
int gameId;
QString description;
QString password;
int maxPlayers;
QList<int> gameTypes;
int activePlayer, activePhase;
bool onlyBuddies, onlyRegistered;
bool spectatorsAllowed;
bool spectatorsNeedPassword;
bool spectatorsCanTalk;
bool spectatorsSeeEverything;
int startingLifeTotal;
bool shareDecklistsOnLoad;
int inactivityCounter;
int startTimeOfThisGame, secondsElapsed;
bool firstGameStarted;
bool turnOrderReversed;
QDateTime startTime;
QTimer *pingClock;
QList<GameReplay *> replayList;
GameReplay *currentReplay;
void createGameStateChangedEvent(Event_GameStateChanged *event,
Server_AbstractParticipant *recipient,
bool omniscient,
bool withUserInfo);
void storeGameInformation();
signals:
void sigStartGameIfReady(bool override);
void gameInfoChanged(ServerInfo_Game gameInfo);
private slots:
void pingClockTimeout();
void doStartGameIfReady(bool forceStartGame = false);
public:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
mutable QRecursiveMutex gameMutex;
#else
mutable QMutex gameMutex;
#endif
Server_Game(const ServerInfo_User &_creatorInfo,
int _gameId,
const QString &_description,
const QString &_password,
int _maxPlayers,
const QList<int> &_gameTypes,
bool _onlyBuddies,
bool _onlyRegistered,
bool _spectatorsAllowed,
bool _spectatorsNeedPassword,
bool _spectatorsCanTalk,
bool _spectatorsSeeEverything,
int _startingLifeTotal,
bool _shareDecklistsOnLoad,
Server_Room *parent);
~Server_Game() override;
Server_Room *getRoom() const
{
return room;
}
void getInfo(ServerInfo_Game &result) const;
int getHostId() const
{
return hostId;
}
ServerInfo_User *getCreatorInfo() const
{
return creatorInfo;
}
bool getGameStarted() const
{
return gameStarted;
}
int getPlayerCount() const;
int getSpectatorCount() const;
QMap<int, Server_Player *> getPlayers() const;
Server_Player *getPlayer(int id) const;
const QMap<int, Server_AbstractParticipant *> &getParticipants() const
{
return participants;
}
int getGameId() const
{
return gameId;
}
QString getDescription() const
{
return description;
}
QString getPassword() const
{
return password;
}
int getMaxPlayers() const
{
return maxPlayers;
}
bool getSpectatorsAllowed() const
{
return spectatorsAllowed;
}
bool getSpectatorsNeedPassword() const
{
return spectatorsNeedPassword;
}
bool getSpectatorsCanTalk() const
{
return spectatorsCanTalk;
}
bool getSpectatorsSeeEverything() const
{
return spectatorsSeeEverything;
}
int getStartingLifeTotal() const
{
return startingLifeTotal;
}
bool getShareDecklistsOnLoad() const
{
return shareDecklistsOnLoad;
}
Response::ResponseCode
checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions, bool asJudge);
bool containsUser(const QString &userName) const;
void addPlayer(Server_AbstractUserInterface *userInterface,
ResponseContainer &rc,
bool spectator,
bool judge,
bool broadcastUpdate = true);
void removeParticipant(Server_AbstractParticipant *participant, Event_Leave::LeaveReason reason);
void removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Player *player);
void unattachCards(GameEventStorage &ges, Server_Player *player);
bool kickParticipant(int playerId);
void startGameIfReady(bool forceStartGame);
void stopGameIfFinished();
int getActivePlayer() const
{
return activePlayer;
}
int getActivePhase() const
{
return activePhase;
}
void setActivePlayer(int _activePlayer);
void setActivePhase(int _activePhase);
void nextTurn();
int getSecondsElapsed() const
{
return secondsElapsed;
}
bool reverseTurnOrder()
{
return turnOrderReversed = !turnOrderReversed;
}
void createGameJoinedEvent(Server_AbstractParticipant *participant, ResponseContainer &rc, bool resuming);
GameEventContainer *
prepareGameEvent(const ::google::protobuf::Message &gameEvent, int playerId, GameEventContext *context = 0);
GameEventContext prepareGameEventContext(const ::google::protobuf::Message &gameEventContext);
void sendGameStateToPlayers();
void sendGameEventContainer(GameEventContainer *cont,
GameEventStorageItem::EventRecipients recipients = GameEventStorageItem::SendToPrivate |
GameEventStorageItem::SendToOthers,
int privatePlayerId = -1);
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,178 @@
#ifndef PLAYER_H
#define PLAYER_H
#include "../../serverinfo_user_container.h"
#include "server_abstract_participant.h"
#include <QList>
#include <QMap>
#include <QString>
class DeckList;
class Server_CardZone;
class Server_Counter;
class Server_Arrow;
class Server_Card;
class CardToMove;
class Server_Player : public Server_AbstractParticipant
{
Q_OBJECT
private:
class MoveCardCompareFunctor;
DeckList *deck;
QMap<QString, Server_CardZone *> zones;
QMap<int, Server_Counter *> counters;
QMap<int, Server_Arrow *> arrows;
QList<int> lastDrawList;
int nextCardId;
bool readyStart;
bool conceded;
bool sideboardLocked;
void revealTopCardIfNeeded(Server_CardZone *zone, GameEventStorage &ges);
void sendCreateTokenEvents(Server_CardZone *zone, Server_Card *card, int xCoord, int yCoord, GameEventStorage &ges);
void getPlayerProperties(ServerInfo_PlayerProperties &result) override;
public:
Server_Player(Server_Game *_game,
int _playerId,
const ServerInfo_User &_userInfo,
bool _judge,
Server_AbstractUserInterface *_handler);
~Server_Player() override;
void prepareDestroy() override;
const DeckList *getDeckList() const
{
return deck;
}
bool getReadyStart() const
{
return readyStart;
}
void setReadyStart(bool _readyStart)
{
readyStart = _readyStart;
}
bool getConceded() const
{
return conceded;
}
void setConceded(bool _conceded)
{
conceded = _conceded;
}
const QMap<QString, Server_CardZone *> &getZones() const
{
return zones;
}
const QMap<int, Server_Counter *> &getCounters() const
{
return counters;
}
const QMap<int, Server_Arrow *> &getArrows() const
{
return arrows;
}
int newCardId();
int newCounterId() const;
int newArrowId() const;
void addZone(Server_CardZone *zone);
void addArrow(Server_Arrow *arrow);
void updateArrowId(int id);
bool deleteArrow(int arrowId);
void addCounter(Server_Counter *counter);
void clearZones();
void setupZones();
Response::ResponseCode drawCards(GameEventStorage &ges, int number);
Response::ResponseCode moveCard(GameEventStorage &ges,
Server_CardZone *startzone,
const QList<const CardToMove *> &_cards,
Server_CardZone *targetzone,
int xCoord,
int yCoord,
bool fixFreeSpaces = true,
bool undoingDraw = false,
bool isReversed = false);
void unattachCard(GameEventStorage &ges, Server_Card *card);
Response::ResponseCode setCardAttrHelper(GameEventStorage &ges,
int targetPlayerId,
const QString &zone,
int cardId,
CardAttribute attribute,
const QString &attrValue,
Server_Card *unzonedCard = nullptr);
Response::ResponseCode
cmdConcede(const Command_Concede &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdUnconcede(const Command_Unconcede &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdReadyStart(const Command_ReadyStart &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdSetSideboardPlan(const Command_SetSideboardPlan &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdSetSideboardLock(const Command_SetSideboardLock &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdShuffle(const Command_Shuffle &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdMulligan(const Command_Mulligan &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdRollDie(const Command_RollDie &cmd, ResponseContainer &rc, GameEventStorage &ges) const override;
Response::ResponseCode
cmdDrawCards(const Command_DrawCards &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdUndoDraw(const Command_UndoDraw &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdMoveCard(const Command_MoveCard &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdFlipCard(const Command_FlipCard &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdCreateToken(const Command_CreateToken &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdCreateArrow(const Command_CreateArrow &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdDeleteArrow(const Command_DeleteArrow &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdSetCardAttr(const Command_SetCardAttr &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdSetCardCounter(const Command_SetCardCounter &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdIncCardCounter(const Command_IncCardCounter &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdIncCounter(const Command_IncCounter &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdCreateCounter(const Command_CreateCounter &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdSetCounter(const Command_SetCounter &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdDelCounter(const Command_DelCounter &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdNextTurn(const Command_NextTurn &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdSetActivePhase(const Command_SetActivePhase &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdDumpZone(const Command_DumpZone &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdRevealCards(const Command_RevealCards &cmd, ResponseContainer &rc, GameEventStorage &ges) override;
Response::ResponseCode
cmdReverseTurn(const Command_ReverseTurn & /*cmd*/, ResponseContainer & /*rc*/, GameEventStorage &ges) override;
Response::ResponseCode cmdChangeZoneProperties(const Command_ChangeZoneProperties &cmd,
ResponseContainer &rc,
GameEventStorage &ges) override;
void getInfo(ServerInfo_Player *info,
Server_AbstractParticipant *playerWhosAsking,
bool omniscient,
bool withUserInfo) override;
};
#endif

View file

@ -0,0 +1,11 @@
#include "server_spectator.h"
Server_Spectator::Server_Spectator(Server_Game *_game,
int _playerId,
const ServerInfo_User &_userInfo,
bool _judge,
Server_AbstractUserInterface *_userInterface)
: Server_AbstractParticipant(_game, _playerId, _userInfo, _judge, _userInterface)
{
spectator = true;
}

View file

@ -0,0 +1,17 @@
#ifndef SPECTATOR_H
#define SPECTATOR_H
#include "server_abstract_participant.h"
class Server_Spectator : public Server_AbstractParticipant
{
Q_OBJECT
public:
Server_Spectator(Server_Game *_game,
int _playerId,
const ServerInfo_User &_userInfo,
bool _judge,
Server_AbstractUserInterface *_handler);
};
#endif