Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { if (authState == NotLoggedIn) return Response::RespLoginNeeded; QMap<int, QPair<int, int> > gameMap = getGames(); if (!gameMap.contains(cont.game_id())) return Response::RespNotInRoom; const QPair<int, int> roomIdAndPlayerId = gameMap.value(cont.game_id()); QReadLocker roomsLocker(&server->roomsLock); Server_Room *room = server->getRooms().value(roomIdAndPlayerId.first); if (!room) return Response::RespNotInRoom; QReadLocker roomGamesLocker(&room->gamesLock); Server_Game *game = room->getGames().value(cont.game_id()); if (!game) { if (room->getExternalGames().contains(cont.game_id())) { server->sendIsl_GameCommand(cont, room->getExternalGames().value(cont.game_id()).server_id(), userInfo->session_id(), roomIdAndPlayerId.first, roomIdAndPlayerId.second ); return Response::RespNothing; } return Response::RespNotInRoom; } QMutexLocker gameLocker(&game->gameMutex); Server_Player *player = game->getPlayers().value(roomIdAndPlayerId.second); if (!player) return Response::RespNotInRoom; GameEventStorage ges; Response::ResponseCode finalResponseCode = Response::RespOk; for (int i = cont.game_command_size() - 1; i >= 0; --i) { const GameCommand &sc = cont.game_command(i); logDebugMessage(QString("game %1 player %2: ").arg(cont.game_id()).arg(roomIdAndPlayerId.second) + QString::fromStdString(sc.ShortDebugString())); Response::ResponseCode resp = player->processGameCommand(sc, rc, ges); if (resp != Response::RespOk) finalResponseCode = resp; } ges.sendToGame(game); return finalResponseCode; }
// This function must only be called from the thread this object lives in. // The thread must not hold any server locks when calling this (e.g. clientsLock, roomsLock). void Server_ProtocolHandler::prepareDestroy() { if (deleted) return; deleted = true; QMapIterator<int, Server_Room *> roomIterator(rooms); while (roomIterator.hasNext()) roomIterator.next().value()->removeClient(this); QMap<int, QPair<int, int> > tempGames(getGames()); server->roomsLock.lockForRead(); QMapIterator<int, QPair<int, int> > gameIterator(tempGames); while (gameIterator.hasNext()) { gameIterator.next(); Server_Room *r = server->getRooms().value(gameIterator.value().first); if (!r) continue; r->gamesLock.lockForRead(); Server_Game *g = r->getGames().value(gameIterator.key()); if (!g) { r->gamesLock.unlock(); continue; } g->gameMutex.lock(); Server_Player *p = g->getPlayers().value(gameIterator.value().second); if (!p) { g->gameMutex.unlock(); r->gamesLock.unlock(); continue; } p->disconnectClient(); g->gameMutex.unlock(); r->gamesLock.unlock(); } server->roomsLock.unlock(); server->removeClient(this); deleteLater(); }
Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { static QList<GameCommand::GameCommandType> antifloodCommandsWhiteList = QList<GameCommand::GameCommandType>() // draw/undo card draw (example: drawing 10 cards one by one from the deck) << GameCommand::DRAW_CARDS << GameCommand::UNDO_DRAW // create, delete arrows (example: targeting with 10 cards during an attack) << GameCommand::CREATE_ARROW << GameCommand::DELETE_ARROW // set card attributes (example: tapping 10 cards at once) << GameCommand::SET_CARD_ATTR // increment / decrement counter (example: -10 life points one by one) << GameCommand::INC_COUNTER // mulling lots of hands in a row << GameCommand::MULLIGAN // allows a user to sideboard without receiving flooding message << GameCommand::MOVE_CARD; if (authState == NotLoggedIn) return Response::RespLoginNeeded; QMap<int, QPair<int, int> > gameMap = getGames(); if (!gameMap.contains(cont.game_id())) return Response::RespNotInRoom; const QPair<int, int> roomIdAndPlayerId = gameMap.value(cont.game_id()); QReadLocker roomsLocker(&server->roomsLock); Server_Room *room = server->getRooms().value(roomIdAndPlayerId.first); if (!room) return Response::RespNotInRoom; QReadLocker roomGamesLocker(&room->gamesLock); Server_Game *game = room->getGames().value(cont.game_id()); if (!game) { if (room->getExternalGames().contains(cont.game_id())) { server->sendIsl_GameCommand(cont, room->getExternalGames().value(cont.game_id()).server_id(), userInfo->session_id(), roomIdAndPlayerId.first, roomIdAndPlayerId.second ); return Response::RespNothing; } return Response::RespNotInRoom; } QMutexLocker gameLocker(&game->gameMutex); Server_Player *player = game->getPlayers().value(roomIdAndPlayerId.second); if (!player) return Response::RespNotInRoom; int commandCountingInterval = server->getCommandCountingInterval(); int maxCommandCountPerInterval = server->getMaxCommandCountPerInterval(); GameEventStorage ges; Response::ResponseCode finalResponseCode = Response::RespOk; for (int i = cont.game_command_size() - 1; i >= 0; --i) { const GameCommand &sc = cont.game_command(i); logDebugMessage(QString("game %1 player %2: ").arg(cont.game_id()).arg(roomIdAndPlayerId.second) + QString::fromStdString(sc.ShortDebugString())); if (commandCountingInterval > 0) { int totalCount = 0; if (commandCountOverTime.isEmpty()) commandCountOverTime.prepend(0); if(!antifloodCommandsWhiteList.contains((GameCommand::GameCommandType) getPbExtension(sc))) ++commandCountOverTime[0]; for (int i = 0; i < commandCountOverTime.size(); ++i) totalCount += commandCountOverTime[i]; if (totalCount > maxCommandCountPerInterval) return Response::RespChatFlood; } Response::ResponseCode resp = player->processGameCommand(sc, rc, ges); if (resp != Response::RespOk) finalResponseCode = resp; } ges.sendToGame(game); return finalResponseCode; }