Ejemplo n.º 1
0
Server_Game::~Server_Game()
{
	room->gamesMutex.lock();
	gameMutex.lock();
	
	gameClosed = true;
	sendGameEventContainer(prepareGameEvent(Event_GameClosed(), -1));
	
	QMapIterator<int, Server_Player *> playerIterator(players);
	while (playerIterator.hasNext())
		playerIterator.next().value()->prepareDestroy();
	players.clear();
	
	room->removeGame(this);
	delete creatorInfo;
	creatorInfo = 0;
	
	gameMutex.unlock();
	room->gamesMutex.unlock();
	
	currentReplay->set_duration_seconds(secondsElapsed - startTimeOfThisGame);
	replayList.append(currentReplay);
	room->getServer()->storeGameInformation(secondsElapsed, allPlayersEver, allSpectatorsEver, replayList);
	
	for (int i = 0; i < replayList.size(); ++i)
		delete replayList[i];
	
	qDebug() << "Server_Game destructor: gameId=" << gameId;
}
Ejemplo n.º 2
0
void Server_Game::createGameJoinedEvent(Server_Player *player, ResponseContainer &rc, bool resuming)
{
	Event_GameJoined event1;
	getInfo(*event1.mutable_game_info());
	event1.set_host_id(hostId);
	event1.set_player_id(player->getPlayerId());
	event1.set_spectator(player->getSpectator());
	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);
	
	QMapIterator<int, Server_Player *> playerIterator(players);
	while (playerIterator.hasNext())
		playerIterator.next().value()->getInfo(event2.add_player_list(), player, player->getSpectator() && spectatorsSeeEverything, true);

	rc.enqueuePostResponseItem(ServerMessage::GAME_EVENT_CONTAINER, prepareGameEvent(event2, -1));
}
Ejemplo n.º 3
0
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.
	QMapIterator<int, Server_Player *> playerIterator(players);
	while (playerIterator.hasNext()) {
		Server_Player *p = playerIterator.next().value();
		QList<Server_Arrow *> arrows = p->getArrows().values();
		QList<Server_Arrow *> toDelete;
		for (int i = 0; i < arrows.size(); ++i) {
			Server_Arrow *a = arrows[i];
			Server_Card *targetCard = qobject_cast<Server_Card *>(a->getTargetItem());
			if (targetCard) {
				if (targetCard->getZone()->getPlayer() == player)
					toDelete.append(a);
			} else if (static_cast<Server_Player *>(a->getTargetItem()) == player)
				toDelete.append(a);
			
			// Don't use else here! It has to happen regardless of whether targetCard == 0.
			if (a->getStartCard()->getZone()->getPlayer() == player)
				toDelete.append(a);
		}
		for (int i = 0; i < toDelete.size(); ++i) {
			Event_DeleteArrow event;
			event.set_arrow_id(toDelete[i]->getId());
			ges.enqueueGameEvent(event, p->getPlayerId());
			
			p->deleteArrow(toDelete[i]->getId());
		}
	}
}
Ejemplo n.º 4
0
void Server_Game::setActivePhase(int _activePhase)
{
	QMutexLocker locker(&gameMutex);
	
	QMapIterator<int, Server_Player *> playerIterator(players);
	while (playerIterator.hasNext()) {
		Server_Player *player = playerIterator.next().value();
		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));
}
Ejemplo n.º 5
0
void Server_Game::stopGameIfFinished()
{
	QMutexLocker locker(&gameMutex);
	
	QMapIterator<int, Server_Player *> playerIterator(players);
	int playing = 0;
	while (playerIterator.hasNext()) {
		Server_Player *p = playerIterator.next().value();
		if (!p->getConceded() && !p->getSpectator())
			++playing;
	}
	if (playing > 1)
		return;

	gameStarted = false;

	playerIterator.toFront();
	while (playerIterator.hasNext()) {
		Server_Player *p = playerIterator.next().value();
		p->clearZones();
		p->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);
}
Ejemplo n.º 6
0
Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions)
{
	Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface();
	{
		QMapIterator<int, Server_Player *> playerIterator(players);
		while (playerIterator.hasNext())
			if (playerIterator.next().value()->getUserInfo()->name() == user->name())
				return Response::RespContextError;
	}
	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)
			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;
}
Ejemplo n.º 7
0
bool Server_Game::containsUser(const QString &userName) const
{
	QMutexLocker locker(&gameMutex);
	
	QMapIterator<int, Server_Player *> playerIterator(players);
	while (playerIterator.hasNext())
		if (playerIterator.next().value()->getUserInfo()->name() == userName.toStdString())
			return true;
	return false;
}
Ejemplo n.º 8
0
int Server_Game::getSpectatorCount() const
{
	QMutexLocker locker(&gameMutex);
	
	QMapIterator<int, Server_Player *> playerIterator(players);
	int result = 0;
	while (playerIterator.hasNext())
		if (playerIterator.next().value()->getSpectator())
			++result;
	return result;
}
Ejemplo n.º 9
0
void Server_Game::createGameStateChangedEvent(Event_GameStateChanged *event, Server_Player *playerWhosAsking, 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);
	
	QMapIterator<int, Server_Player *> playerIterator(players);
	while (playerIterator.hasNext())
		playerIterator.next().value()->getInfo(event->add_player_list(), playerWhosAsking, omniscient, withUserInfo);
}
Ejemplo n.º 10
0
void Server_Game::removePlayer(Server_Player *player)
{
	room->getServer()->removePersistentPlayer(QString::fromStdString(player->getUserInfo()->name()), room->getId(), gameId, player->getPlayerId());
	players.remove(player->getPlayerId());
	
	GameEventStorage ges;
	removeArrowsRelatedToPlayer(ges, player);
	unattachCards(ges, player);
	ges.enqueueGameEvent(Event_Leave(), player->getPlayerId());
	ges.sendToGame(this);
	
	bool playerActive = activePlayer == player->getPlayerId();
	bool playerHost = hostId == player->getPlayerId();
	bool spectator = player->getSpectator();
	player->prepareDestroy();
	
	if (!getPlayerCount()) {
		gameClosed = true;
		deleteLater();
		return;
	} else if (!spectator) {
		if (playerHost) {
			int newHostId = -1;
			QMapIterator<int, Server_Player *> playerIterator(players);
			while (playerIterator.hasNext()) {
				Server_Player *p = playerIterator.next().value();
				if (!p->getSpectator()) {
					newHostId = p->getPlayerId();
					break;
				}
			}
			if (newHostId != -1) {
				hostId = newHostId;
				sendGameEventContainer(prepareGameEvent(Event_GameHostChanged(), hostId));
			}
		}
		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);
}
Ejemplo n.º 11
0
void Server_Game::pingClockTimeout()
{
	QMutexLocker locker(&gameMutex);
	++secondsElapsed;
	
	GameEventStorage ges;
	ges.setGameEventContext(Context_PingChanged());
	
	QList<ServerInfo_PlayerPing *> pingList;
	QMapIterator<int, Server_Player *> playerIterator(players);
	bool allPlayersInactive = true;
	int playerCount = 0;
	while (playerIterator.hasNext()) {
		Server_Player *player = playerIterator.next().value();
		if (!player->getSpectator())
			++playerCount;
		
		const int oldPingTime = player->getPingTime();
		player->playerMutex.lock();
		int newPingTime;
		if (player->getUserInterface())
			newPingTime = player->getUserInterface()->getLastCommandTime();
		else
			newPingTime = -1;
		player->playerMutex.unlock();
		
		if ((newPingTime != -1) && !player->getSpectator())
			allPlayersInactive = false;
		
		if ((abs(oldPingTime - newPingTime) > 1) || ((newPingTime == -1) && (oldPingTime != -1)) || ((newPingTime != -1) && (oldPingTime == -1))) {
			player->setPingTime(newPingTime);
			
			Event_PlayerPropertiesChanged event;
			event.mutable_player_properties()->set_ping_seconds(newPingTime);
			ges.enqueueGameEvent(event, player->getPlayerId());
		}
	}
	ges.sendToGame(this);
	
	const int maxTime = room->getServer()->getMaxGameInactivityTime();
	if (allPlayersInactive) {
		if (((++inactivityCounter >= maxTime) && (maxTime > 0)) || (playerCount < maxPlayers))
			deleteLater();
	} else
		inactivityCounter = 0;
}
Ejemplo n.º 12
0
void Server_Game::sendGameEventContainer(GameEventContainer *cont, GameEventStorageItem::EventRecipients recipients, int privatePlayerId)
{
	QMutexLocker locker(&gameMutex);
	
	cont->set_game_id(gameId);
	QMapIterator<int, Server_Player *> playerIterator(players);
	while (playerIterator.hasNext()) {
		Server_Player *p = playerIterator.next().value();
		const bool playerPrivate = (p->getPlayerId() == privatePlayerId) || (p->getSpectator() && spectatorsSeeEverything);
		if ((recipients.testFlag(GameEventStorageItem::SendToPrivate) && playerPrivate) || (recipients.testFlag(GameEventStorageItem::SendToOthers) && !playerPrivate))
			p->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;
}
Ejemplo n.º 13
0
void Server_Game::sendGameStateToPlayers()
{
	// game state information for replay and omniscient spectators
	Event_GameStateChanged omniscientEvent;
	createGameStateChangedEvent(&omniscientEvent, 0, 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 spectatorEvent;
	if (spectatorsSeeEverything)
		spectatorEvent = omniscientEvent;
	else
		createGameStateChangedEvent(&spectatorEvent, 0, false, false);
	
	// send game state info to clients according to their role in the game
	QMapIterator<int, Server_Player *> playerIterator(players);
	while (playerIterator.hasNext()) {
		Server_Player *player = playerIterator.next().value();
		GameEventContainer *gec;
		if (player->getSpectator())
			gec = prepareGameEvent(spectatorEvent, -1);
		else {
			Event_GameStateChanged event;
			createGameStateChangedEvent(&event, player, false, false);
			
			gec = prepareGameEvent(event, -1);
		}
		player->sendGameEvent(*gec);
		delete gec;
	}
}
Ejemplo n.º 14
0
void Server_Game::doStartGameIfReady()
{
	Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface();
	QMutexLocker locker(&gameMutex);
	
	if (getPlayerCount() < maxPlayers)
		return;
	QMapIterator<int, Server_Player *> playerIterator(players);
	while (playerIterator.hasNext()) {
		Server_Player *p = playerIterator.next().value();
		if (!p->getReadyStart() && !p->getSpectator())
			return;
	}
	playerIterator.toFront();
	while (playerIterator.hasNext()) {
		Server_Player *p = playerIterator.next().value();
		if (!p->getSpectator())
			p->setupZones();
	}

	gameStarted = true;
	playerIterator.toFront();
	while (playerIterator.hasNext()) {
		Server_Player *player = playerIterator.next().value();
		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, 0, 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 Servatrice_DatabaseInterface::storeGameInformation(const QString &roomName, const QStringList &roomGameTypes, const ServerInfo_Game &gameInfo, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const QList<GameReplay *> &replayList)
{
	if (!checkSql())
		return;
	
	QVariantList gameIds1, playerNames, gameIds2, userIds, replayNames;
	QSetIterator<QString> playerIterator(allPlayersEver);
	while (playerIterator.hasNext()) {
		gameIds1.append(gameInfo.game_id());
		const QString &playerName = playerIterator.next();
		playerNames.append(playerName);
	}
	QSet<QString> allUsersInGame = allPlayersEver + allSpectatorsEver;
	QSetIterator<QString> allUsersIterator(allUsersInGame);
	while (allUsersIterator.hasNext()) {
		int id = getUserIdInDB(allUsersIterator.next());
		if (id == -1)
			continue;
		gameIds2.append(gameInfo.game_id());
		userIds.append(id);
		replayNames.append(QString::fromStdString(gameInfo.description()));
	}
	
	QVariantList replayIds, replayGameIds, replayDurations, replayBlobs;
	for (int i = 0; i < replayList.size(); ++i) {
		QByteArray blob;
		const unsigned int size = replayList[i]->ByteSize();
		blob.resize(size);
		replayList[i]->SerializeToArray(blob.data(), size);
		
		replayIds.append(QVariant((qulonglong) replayList[i]->replay_id()));
		replayGameIds.append(gameInfo.game_id());
		replayDurations.append(replayList[i]->duration_seconds());
		replayBlobs.append(blob);
	}
	
	{
		QSqlQuery query(sqlDatabase);
		query.prepare("update " + server->getDbPrefix() + "_games set room_name=:room_name, descr=:descr, creator_name=:creator_name, password=:password, game_types=:game_types, player_count=:player_count, time_finished=now() where id=:id_game");
		query.bindValue(":room_name", roomName);
		query.bindValue(":id_game", gameInfo.game_id());
		query.bindValue(":descr", QString::fromStdString(gameInfo.description()));
		query.bindValue(":creator_name", QString::fromStdString(gameInfo.creator_info().name()));
		query.bindValue(":password", gameInfo.with_password() ? 1 : 0);
		query.bindValue(":game_types", roomGameTypes.isEmpty() ? QString("") : roomGameTypes.join(", "));
		query.bindValue(":player_count", gameInfo.max_players());
		if (!execSqlQuery(query))
			return;
	}
	{
		QSqlQuery query(sqlDatabase);
		query.prepare("insert into " + server->getDbPrefix() + "_games_players (id_game, player_name) values (:id_game, :player_name)");
		query.bindValue(":id_game", gameIds1);
		query.bindValue(":player_name", playerNames);
		query.execBatch();
	}
	{
		QSqlQuery query(sqlDatabase);
		query.prepare("update " + server->getDbPrefix() + "_replays set id_game=:id_game, duration=:duration, replay=:replay where id=:id_replay");
		query.bindValue(":id_replay", replayIds);
		query.bindValue(":id_game", replayGameIds);
		query.bindValue(":duration", replayDurations);
		query.bindValue(":replay", replayBlobs);
		query.execBatch();
	}
	{
		QSqlQuery query(sqlDatabase);
		query.prepare("insert into " + server->getDbPrefix() + "_replays_access (id_game, id_player, replay_name) values (:id_game, :id_player, :replay_name)");
		query.bindValue(":id_game", gameIds2);
		query.bindValue(":id_player", userIds);
		query.bindValue(":replay_name", replayNames);
		query.execBatch();
	}
}
Ejemplo n.º 16
0
ResponseCode Server_ProtocolHandler::cmdAttachCard(Command_AttachCard *cmd, CommandContainer *cont, Server_Game *game, Server_Player *player)
{
	if (player->getSpectator())
		return RespFunctionNotAllowed;
	
	if (!game->getGameStarted())
		return RespGameNotStarted;
		
	Server_CardZone *startzone = player->getZones().value(cmd->getStartZone());
	if (!startzone)
		return RespNameNotFound;
	
	Server_Card *card = startzone->getCard(cmd->getCardId(), false);
	if (!card)
		return RespNameNotFound;

	int playerId = cmd->getTargetPlayerId();
	Server_Player *targetPlayer = 0;
	Server_CardZone *targetzone = 0;
	Server_Card *targetCard = 0;
	
	if (playerId != -1) {
		targetPlayer = game->getPlayer(cmd->getTargetPlayerId());
		if (!targetPlayer)
			return RespNameNotFound;
	} else if (!card->getParentCard())
		return RespContextError;
	if (targetPlayer)
		targetzone = targetPlayer->getZones().value(cmd->getTargetZone());
	if (targetzone) {
		// This is currently enough to make sure cards don't get attached to a card that is not on the table.
		// Possibly a flag will have to be introduced for this sometime.
		if (!targetzone->hasCoords())
			return RespContextError;
		targetCard = targetzone->getCard(cmd->getTargetCardId(), false);
		if (targetCard)
			if (targetCard->getParentCard())
				return RespContextError;
	}
	if (!startzone->hasCoords())
		return RespContextError;
	
	// Get all arrows pointing to or originating from the card being attached and delete them.
	QMapIterator<int, Server_Player *> playerIterator(game->getPlayers());
	while (playerIterator.hasNext()) {
		Server_Player *p = playerIterator.next().value();
		QList<Server_Arrow *> arrows = p->getArrows().values();
		QList<Server_Arrow *> toDelete;
		for (int i = 0; i < arrows.size(); ++i) {
			Server_Arrow *a = arrows[i];
			Server_Card *tCard = qobject_cast<Server_Card *>(a->getTargetItem());
			if ((tCard == card) || (a->getStartCard() == card))
				toDelete.append(a);
		}
		for (int i = 0; i < toDelete.size(); ++i) {
			cont->enqueueGameEventPrivate(new Event_DeleteArrow(p->getPlayerId(), toDelete[i]->getId()), game->getGameId());
			cont->enqueueGameEventPublic(new Event_DeleteArrow(p->getPlayerId(), toDelete[i]->getId()), game->getGameId());
			p->deleteArrow(toDelete[i]->getId());
		}
	}

	if (targetCard) {
		// Unattach all cards attached to the card being attached.
		const QList<Server_Card *> &attachedList = card->getAttachedCards();
		for (int i = 0; i < attachedList.size(); ++i)
			player->unattachCard(cont, attachedList[i]);
		
		if (targetzone->isColumnStacked(targetCard->getX(), targetCard->getY()))
			targetPlayer->moveCard(cont, targetzone, QList<int>() << targetCard->getId(), targetzone, targetzone->getFreeGridColumn(-2, targetCard->getY(), targetCard->getName()), targetCard->getY(), targetCard->getFaceDown(), false);
		
		card->setParentCard(targetCard);
		card->setCoords(-1, card->getY());
		cont->enqueueGameEventPrivate(new Event_AttachCard(player->getPlayerId(), startzone->getName(), card->getId(), targetPlayer->getPlayerId(), targetzone->getName(), targetCard->getId()), game->getGameId());
		cont->enqueueGameEventPublic(new Event_AttachCard(player->getPlayerId(), startzone->getName(), card->getId(), targetPlayer->getPlayerId(), targetzone->getName(), targetCard->getId()), game->getGameId());
	} else
		player->unattachCard(cont, card);
	
	return RespOk;
}