1 /*****************************************************************************
2 * PokerTH - The open source texas holdem engine *
3 * Copyright (C) 2006-2012 Felix Hammer, Florian Thauer, Lothar May *
4 * *
5 * This program is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU Affero General Public License as *
7 * published by the Free Software Foundation, either version 3 of the *
8 * License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU Affero General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Affero General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 * *
18 * *
19 * Additional permission under GNU AGPL version 3 section 7 *
20 * *
21 * If you modify this program, or any covered work, by linking or *
22 * combining it with the OpenSSL project's OpenSSL library (or a *
23 * modified version of that library), containing parts covered by the *
24 * terms of the OpenSSL or SSLeay licenses, the authors of PokerTH *
25 * (Felix Hammer, Florian Thauer, Lothar May) grant you additional *
26 * permission to convey the resulting work. *
27 * Corresponding Source for a non-source form of such a combination *
28 * shall include the source code for the parts of OpenSSL used as well *
29 * as that of the covered work. *
30 *****************************************************************************/
31
32 #include <boost/asio.hpp>
33 #include <boost/bind.hpp>
34 #include <algorithm>
35
36 #include <net/servergame.h>
37 #include <net/servergamestate.h>
38 #include <net/serverlobbythread.h>
39 #include <net/serverexception.h>
40 #include <net/senderhelper.h>
41 #include <net/socket_msg.h>
42 #include <core/loghelper.h>
43 #include <db/serverdbinterface.h>
44 #include <db/serverdbnoaction.h>
45 #include <game.h>
46 #include <localenginefactory.h>
47 #include <tools.h>
48 #include <configfile.h>
49
50
51 #define SERVER_CHECK_VOTE_KICK_INTERVAL_MSEC 500
52 #define SERVER_KICK_TIMEOUT_ADD_DELAY_SEC 2
53
54 using namespace std;
55
56 #ifdef BOOST_ASIO_HAS_STD_CHRONO
57 using namespace std::chrono;
58 #else
59 using namespace boost::chrono;
60 #endif
61
LessThanPlayerHandStartMoney(const boost::shared_ptr<PlayerInterface> p1,const boost::shared_ptr<PlayerInterface> p2)62 static bool LessThanPlayerHandStartMoney(const boost::shared_ptr<PlayerInterface> p1, const boost::shared_ptr<PlayerInterface> p2)
63 {
64 return p1->getMyRoundStartCash() < p2->getMyRoundStartCash();
65 }
66
67
ServerGame(boost::shared_ptr<ServerLobbyThread> lobbyThread,u_int32_t id,const string & name,const string & pwd,const GameData & gameData,unsigned adminPlayerId,unsigned creatorPlayerDBId,GuiInterface & gui,ConfigFile & playerConfig)68 ServerGame::ServerGame(boost::shared_ptr<ServerLobbyThread> lobbyThread, u_int32_t id, const string &name, const string &pwd, const GameData &gameData,
69 unsigned adminPlayerId, unsigned creatorPlayerDBId, GuiInterface &gui, ConfigFile &playerConfig)
70 : m_adminPlayerId(adminPlayerId), m_lobbyThread(lobbyThread), m_gui(gui),
71 m_gameData(gameData), m_curState(NULL), m_id(id), m_name(name),
72 m_password(pwd), m_creatorPlayerDBId(creatorPlayerDBId), m_playerConfig(playerConfig),
73 m_gameNum(1), m_curPetitionId(1), m_voteKickTimer(lobbyThread->GetIOService()),
74 m_stateTimer1(lobbyThread->GetIOService()), m_stateTimer2(lobbyThread->GetIOService()),
75 m_isNameReported(false)
76 {
77 LOG_VERBOSE("Game object " << GetId() << " created.");
78 }
79
~ServerGame()80 ServerGame::~ServerGame()
81 {
82 LOG_VERBOSE("Game object " << GetId() << " destructed.");
83 }
84
85 void
Init()86 ServerGame::Init()
87 {
88 SetState(SERVER_INITIAL_STATE::Instance());
89 }
90
91 void
Exit()92 ServerGame::Exit()
93 {
94 m_voteKickTimer.cancel();
95 SetState(ServerGameStateFinal::Instance());
96 }
97
98 u_int32_t
GetId() const99 ServerGame::GetId() const
100 {
101 return m_id;
102 }
103
104 const std::string &
GetName() const105 ServerGame::GetName() const
106 {
107 return m_name;
108 }
109
110 unsigned
GetCreatorDBId() const111 ServerGame::GetCreatorDBId() const
112 {
113 return m_creatorPlayerDBId;
114 }
115
116 void
AddSession(boost::shared_ptr<SessionData> session,bool spectateOnly)117 ServerGame::AddSession(boost::shared_ptr<SessionData> session, bool spectateOnly)
118 {
119 if (session) {
120 if (spectateOnly) {
121 GetState().HandleNewSpectator(shared_from_this(), session);
122 } else {
123 GetState().HandleNewPlayer(shared_from_this(), session);
124 }
125 }
126 }
127
128 void
RemovePlayer(unsigned playerId,unsigned errorCode)129 ServerGame::RemovePlayer(unsigned playerId, unsigned errorCode)
130 {
131 boost::shared_ptr<SessionData> tmpSession = GetSessionManager().GetSessionByUniquePlayerId(playerId);
132 // Only kick if the player was found.
133 if (tmpSession)
134 SessionError(tmpSession, errorCode);
135 }
136
137 void
MutePlayer(unsigned playerId,bool mute)138 ServerGame::MutePlayer(unsigned playerId, bool mute)
139 {
140 if (m_game) {
141 boost::shared_ptr<PlayerInterface> tmpPlayer(m_game->getPlayerByUniqueId(playerId));
142 if (tmpPlayer) {
143 tmpPlayer->setIsMuted(mute);
144 }
145 }
146 }
147
148 void
MarkPlayerAsInactive(unsigned playerId)149 ServerGame::MarkPlayerAsInactive(unsigned playerId)
150 {
151 if (m_game) {
152 boost::shared_ptr<PlayerInterface> tmpPlayer(m_game->getPlayerByUniqueId(playerId));
153 if (tmpPlayer) {
154 tmpPlayer->setIsSessionActive(false);
155 }
156 }
157 }
158
159 void
MarkPlayerAsKicked(unsigned playerId)160 ServerGame::MarkPlayerAsKicked(unsigned playerId)
161 {
162 // Mark the player as kicked in the engine.
163 if (m_game) {
164 boost::shared_ptr<PlayerInterface> tmpPlayer(m_game->getPlayerByUniqueId(playerId));
165 if (tmpPlayer) {
166 // Player was kicked, so he is not allowed to rejoin.
167 tmpPlayer->setIsKicked(true);
168 tmpPlayer->setMyGuid("");
169 }
170 }
171 }
172
173 void
HandlePacket(boost::shared_ptr<SessionData> session,boost::shared_ptr<NetPacket> packet)174 ServerGame::HandlePacket(boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet)
175 {
176 if (session && packet)
177 GetState().ProcessPacket(shared_from_this(), session, packet);
178 }
179
180 GameState
GetCurRound() const181 ServerGame::GetCurRound() const
182 {
183 return static_cast<GameState>(GetGame().getCurrentHand()->getCurrentRound());
184 }
185
186 void
SendToAllPlayers(boost::shared_ptr<NetPacket> packet,int state)187 ServerGame::SendToAllPlayers(boost::shared_ptr<NetPacket> packet, int state)
188 {
189 GetSessionManager().SendToAllSessions(GetLobbyThread().GetSender(), packet, state);
190 }
191
192 void
SendToAllButOnePlayers(boost::shared_ptr<NetPacket> packet,SessionId except,int state)193 ServerGame::SendToAllButOnePlayers(boost::shared_ptr<NetPacket> packet, SessionId except, int state)
194 {
195 GetSessionManager().SendToAllButOneSessions(GetLobbyThread().GetSender(), packet, except, state);
196 }
197
198 void
RemoveAllSessions()199 ServerGame::RemoveAllSessions()
200 {
201 // Clean up ALL sessions which are left.
202 GetSessionManager().ForEach(&SessionData::Close);
203 GetSessionManager().Clear();
204 SetState(ServerGameStateFinal::Instance());
205 }
206
207 void
MoveSpectatorsToLobby()208 ServerGame::MoveSpectatorsToLobby()
209 {
210 PlayerIdList spectatorList = GetSpectatorIdList();
211 PlayerIdList::const_iterator i = spectatorList.begin();
212 PlayerIdList::const_iterator end = spectatorList.end();
213 while (i != end) {
214 boost::shared_ptr<SessionData> tmpSession = GetSessionManager().GetSessionByUniquePlayerId(*i);
215 // Only remove if the spectator was found.
216 if (tmpSession)
217 MoveSessionToLobby(tmpSession, NTF_NET_REMOVED_GAME_CLOSED);
218 ++i;
219 }
220 }
221
222 void
TimerVoteKick(const boost::system::error_code & ec)223 ServerGame::TimerVoteKick(const boost::system::error_code &ec)
224 {
225 if (!ec && m_curState != &ServerGameStateFinal::Instance()) {
226 // Check whether someone should be kicked, or whether a vote kick should be aborted.
227 // Only one vote kick can be active at a time.
228 if (m_voteKickData) {
229 // Prepare some values.
230 const PlayerIdList playerIds(GetPlayerIdList());
231 int votesRequiredToKick = m_voteKickData->numVotesToKick - m_voteKickData->numVotesInFavourOfKicking;
232 int playersAllowedToVote = 0;
233 // We need to count the number of players which are still allowed to vote.
234 PlayerIdList::const_iterator player_i = playerIds.begin();
235 PlayerIdList::const_iterator player_end = playerIds.end();
236 while (player_i != player_end) {
237 if (find(m_voteKickData->votedPlayerIds.begin(), m_voteKickData->votedPlayerIds.end(), *player_i) == m_voteKickData->votedPlayerIds.end())
238 playersAllowedToVote++;
239 ++player_i;
240 }
241 bool abortPetition = false;
242 bool doKick = false;
243 EndPetitionReason reason;
244
245 // 1. Enough votes to kick the player.
246 if (m_voteKickData->numVotesInFavourOfKicking >= m_voteKickData->numVotesToKick) {
247 reason = PETITION_END_ENOUGH_VOTES;
248 abortPetition = true;
249 doKick = true;
250 }
251 // 2. Several players left the game, so a kick is no longer possible.
252 else if (votesRequiredToKick > playersAllowedToVote) {
253 reason = PETITION_END_NOT_ENOUGH_PLAYERS;
254 abortPetition = true;
255 }
256 // 3. The kick has become invalid because the player to be kicked left.
257 else if (!IsValidPlayer(m_voteKickData->kickPlayerId)) {
258 reason = PETITION_END_PLAYER_LEFT;
259 abortPetition = true;
260 }
261 // 4. A kick request timed out (because not everyone voted).
262 else if (m_voteKickData->voteTimer.elapsed().total_seconds() >= m_voteKickData->timeLimitSec) {
263 reason = PETITION_END_TIMEOUT;
264 abortPetition = true;
265 }
266 if (abortPetition) {
267 boost::shared_ptr<NetPacket> packet(new NetPacket);
268 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_EndKickPetitionMessage);
269 EndKickPetitionMessage *netEndPetition = packet->GetMsg()->mutable_endkickpetitionmessage();
270 netEndPetition->set_gameid(GetId());
271 netEndPetition->set_petitionid(m_voteKickData->petitionId);
272 netEndPetition->set_numvotesagainstkicking(m_voteKickData->numVotesAgainstKicking);
273 netEndPetition->set_numvotesinfavourofkicking(m_voteKickData->numVotesInFavourOfKicking);
274 netEndPetition->set_resultplayerkicked(doKick);
275 netEndPetition->set_petitionendreason(static_cast<EndKickPetitionMessage::PetitionEndReason>(reason));
276 SendToAllPlayers(packet, SessionData::Game);
277
278 // Perform kick.
279 if (doKick)
280 KickPlayer(m_voteKickData->kickPlayerId);
281 // This petition has ended.
282 m_voteKickData.reset();
283 }
284 m_voteKickTimer.expires_from_now(
285 milliseconds(SERVER_CHECK_VOTE_KICK_INTERVAL_MSEC));
286 m_voteKickTimer.async_wait(
287 boost::bind(
288 &ServerGame::TimerVoteKick, shared_from_this(), boost::asio::placeholders::error));
289 }
290 }
291 }
292
293 PlayerDataList
InternalStartGame()294 ServerGame::InternalStartGame()
295 {
296 // Initialize the game.
297 PlayerDataList playerData(GetFullPlayerDataList());
298
299 if (playerData.size() >= 2) {
300 // Set DB Backend.
301 if (GetGameData().gameType == GAME_TYPE_RANKING)
302 m_database = GetLobbyThread().GetDatabase();
303 else
304 m_database.reset(new ServerDBNoAction);
305
306 // Randomize player list.
307 // Note: This does not use a cryptographically strong
308 // random number generator.
309 vector<boost::shared_ptr<PlayerData> > tmpData(playerData.begin(), playerData.end());
310 random_shuffle(tmpData.begin(), tmpData.end());
311 copy(tmpData.begin(), tmpData.end(), playerData.begin());
312
313 // Set order of players.
314 AssignPlayerNumbers(playerData);
315
316 // Create EngineFactory
317 boost::shared_ptr<EngineFactory> factory(new LocalEngineFactory(&m_playerConfig)); // LocalEngine erstellen
318
319 // Set start data.
320 StartData startData;
321 startData.numberOfPlayers = (int)playerData.size();
322
323 int tmpDealerPos = 0;
324 Tools::GetRand(0, startData.numberOfPlayers-1, 1, &tmpDealerPos);
325 // The Player Id is not continuous. Therefore, the start dealer position
326 // needs to be converted to a player Id, and cannot be directly generated
327 // as player Id.
328 PlayerDataList::const_iterator player_i = playerData.begin();
329 PlayerDataList::const_iterator player_end = playerData.end();
330
331 int tmpPos = 0;
332 while (player_i != player_end) {
333 startData.startDealerPlayerId = static_cast<unsigned>((*player_i)->GetUniqueId());
334 if (tmpPos == tmpDealerPos)
335 break;
336 ++tmpPos;
337 ++player_i;
338 }
339 if (player_i == player_end)
340 throw ServerException(__FILE__, __LINE__, ERR_NET_DEALER_NOT_FOUND, 0);
341
342 SetStartData(startData);
343
344 GuiInterface &gui = GetGui();
345 m_game.reset(new Game(&gui, factory, playerData, GetGameData(), GetStartData(), GetNextGameNum(), NULL));
346
347 GetDatabase().AsyncCreateGame(GetId(), GetName());
348 InitRankingMap(playerData);
349 }
350 return playerData;
351 }
352
353 void
InitRankingMap(const PlayerDataList & playerDataList)354 ServerGame::InitRankingMap(const PlayerDataList &playerDataList)
355 {
356 PlayerDataList::const_iterator i = playerDataList.begin();
357 PlayerDataList::const_iterator end = playerDataList.end();
358 while (i != end) {
359 boost::shared_ptr<PlayerData> tmpPlayer(*i);
360 RankingData tmpData(tmpPlayer->GetDBId());
361 m_rankingMap[tmpPlayer->GetUniqueId()] = tmpData;
362 ++i;
363 }
364 }
365
366 void
UpdateRankingMap()367 ServerGame::UpdateRankingMap()
368 {
369 list<boost::shared_ptr<PlayerInterface> > activePlayers = *m_game->getActivePlayerList();
370 int currentRank = static_cast<int>(activePlayers.size());
371 list<boost::shared_ptr<PlayerInterface> > tmpRemovedPlayers;
372 PlayerListIterator active_i = activePlayers.begin();
373 PlayerListIterator active_end = activePlayers.end();
374 PlayerListIterator next_active_i = active_i;
375 while(active_i != active_end) {
376 ++next_active_i;
377 if ((*active_i)->getMyCash() < 1) {
378 tmpRemovedPlayers.push_back(*active_i);
379 activePlayers.erase(active_i);
380 }
381 active_i = next_active_i;
382 }
383
384 if (!tmpRemovedPlayers.empty()) {
385 tmpRemovedPlayers.sort(LessThanPlayerHandStartMoney);
386 PlayerListConstIterator removed_i = tmpRemovedPlayers.begin();
387 PlayerListConstIterator removed_end = tmpRemovedPlayers.end();
388 PlayerListConstIterator next_removed_i = removed_i;
389 int currentRankCounter = 0;
390 while (removed_i != removed_end) {
391 ++next_removed_i;
392
393 SetPlayerPlace((*removed_i)->getMyUniqueID(), currentRank);
394 ++currentRankCounter;
395 if (next_removed_i != removed_end && (*removed_i)->getMyRoundStartCash() < (*next_removed_i)->getMyRoundStartCash()) {
396 currentRank -= currentRankCounter;
397 currentRankCounter = 0;
398 }
399
400 removed_i = next_removed_i;
401 }
402 }
403 // Last player is winner.
404 if (activePlayers.size() == 1) {
405 SetPlayerPlace((*(activePlayers.begin()))->getMyUniqueID(), 1);
406 }
407 }
408
409 void
SetPlayerPlace(unsigned playerId,int place)410 ServerGame::SetPlayerPlace(unsigned playerId, int place)
411 {
412 RankingMap::iterator pos = m_rankingMap.find(playerId);
413 if (pos != m_rankingMap.end()) {
414 (*pos).second.place = place;
415 }
416 }
417
418 void
ReplaceRankingPlayer(unsigned oldPlayerId,unsigned newPlayerId)419 ServerGame::ReplaceRankingPlayer(unsigned oldPlayerId, unsigned newPlayerId)
420 {
421 RankingMap::iterator pos = m_rankingMap.find(oldPlayerId);
422 if (pos != m_rankingMap.end()) {
423 RankingData tmpData((*pos).second);
424 m_rankingMap[newPlayerId] = tmpData;
425 m_rankingMap.erase(pos);
426 }
427 }
428
429 void
StoreAndResetRanking()430 ServerGame::StoreAndResetRanking()
431 {
432 // Store players in database.
433 RankingMap::const_iterator i = m_rankingMap.begin();
434 RankingMap::const_iterator end = m_rankingMap.end();
435 while (i != end) {
436 if ((*i).second.dbid != DB_ID_INVALID) {
437 GetDatabase().SetGamePlayerPlace(GetId(), (*i).second.dbid, (*i).second.place);
438 }
439 ++i;
440 }
441 GetDatabase().EndGame(GetId());
442 m_rankingMap.clear();
443 }
444
445 void
RemoveAutoLeavePlayers()446 ServerGame::RemoveAutoLeavePlayers()
447 {
448 boost::mutex::scoped_lock lock(m_autoLeavePlayerListMutex);
449 PlayerIdList::const_iterator i = m_autoLeavePlayerList.begin();
450 PlayerIdList::const_iterator end = m_autoLeavePlayerList.end();
451 while (i != end) {
452 boost::shared_ptr<SessionData> tmpSession = GetSessionManager().GetSessionByUniquePlayerId(*i);
453 // Only remove if the player was found.
454 if (tmpSession)
455 MoveSessionToLobby(tmpSession, NTF_NET_REMOVED_ON_REQUEST);
456 ++i;
457 }
458 m_autoLeavePlayerList.clear();
459 }
460
461 void
InternalEndGame()462 ServerGame::InternalEndGame()
463 {
464 StoreAndResetRanking();
465 m_game.reset();
466 m_numJoinsPerPlayer.clear();
467 }
468
469 void
KickPlayer(unsigned playerId)470 ServerGame::KickPlayer(unsigned playerId)
471 {
472 MarkPlayerAsKicked(playerId);
473
474 // Kick the network session from this game.
475 boost::shared_ptr<SessionData> tmpSession(GetSessionManager().GetSessionByUniquePlayerId(playerId));
476 // Only kick if the player was found.
477 if (tmpSession) {
478 MoveSessionToLobby(tmpSession, NTF_NET_REMOVED_KICKED);
479 }
480 // KICKING COMPUTER PLAYERS IS BUGGY AND OCCASIONALLY CAUSES A CRASH
481 // Disabled for now.
482 //else
483 //{
484 // boost::shared_ptr<PlayerData> tmpData(RemoveComputerPlayer(playerId));
485 // if (tmpData)
486 // RemovePlayerData(tmpData, NTF_NET_REMOVED_KICKED);
487 //}
488 }
489
490 void
InternalAskVoteKick(boost::shared_ptr<SessionData> byWhom,unsigned playerIdWho,unsigned timeoutSec)491 ServerGame::InternalAskVoteKick(boost::shared_ptr<SessionData> byWhom, unsigned playerIdWho, unsigned timeoutSec)
492 {
493 if (IsRunning() && byWhom->GetPlayerData()) {
494 // Retrieve only the number of human players.
495 size_t numPlayers = GetSessionManager().GetPlayerIdList(SessionData::Game).size();
496 if (numPlayers > 2) {
497 // Check whether the player to be kicked exists.
498 if (IsValidPlayer(playerIdWho)) {
499 // Lock the vote kick data.
500 if (!m_voteKickData) {
501 // Initiate a vote kick.
502 unsigned playerIdByWhom = byWhom->GetPlayerData()->GetUniqueId();
503 m_voteKickData.reset(new VoteKickData);
504 m_voteKickData->petitionId = m_curPetitionId++;
505 m_voteKickData->kickPlayerId = playerIdWho;
506 m_voteKickData->numVotesToKick = static_cast<int>(ceil(numPlayers / 3. * 2.));
507 m_voteKickData->timeLimitSec = timeoutSec + SERVER_KICK_TIMEOUT_ADD_DELAY_SEC;
508 // Consider first vote.
509 m_voteKickData->numVotesInFavourOfKicking = 1;
510 m_voteKickData->votedPlayerIds.push_back(playerIdByWhom);
511
512 boost::shared_ptr<NetPacket> packet(new NetPacket);
513 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_StartKickPetitionMessage);
514 StartKickPetitionMessage *netStartPetition = packet->GetMsg()->mutable_startkickpetitionmessage();
515 netStartPetition->set_gameid(GetId());
516 netStartPetition->set_petitionid(m_voteKickData->petitionId);
517 netStartPetition->set_proposingplayerid(playerIdByWhom);
518 netStartPetition->set_kickplayerid(m_voteKickData->kickPlayerId);
519 netStartPetition->set_kicktimeoutsec(timeoutSec);
520 netStartPetition->set_numvotesneededtokick(m_voteKickData->numVotesToKick);
521 SendToAllPlayers(packet, SessionData::Game);
522
523 m_voteKickTimer.expires_from_now(
524 milliseconds(SERVER_CHECK_VOTE_KICK_INTERVAL_MSEC));
525 m_voteKickTimer.async_wait(
526 boost::bind(
527 &ServerGame::TimerVoteKick, shared_from_this(), boost::asio::placeholders::error));
528
529 } else
530 InternalDenyAskVoteKick(byWhom, playerIdWho, KICK_DENIED_OTHER_IN_PROGRESS);
531 } else
532 InternalDenyAskVoteKick(byWhom, playerIdWho, KICK_DENIED_INVALID_PLAYER_ID);
533 } else
534 InternalDenyAskVoteKick(byWhom, playerIdWho, KICK_DENIED_TOO_FEW_PLAYERS);
535 } else
536 InternalDenyAskVoteKick(byWhom, playerIdWho, KICK_DENIED_INVALID_STATE);
537 }
538
539 void
InternalDenyAskVoteKick(boost::shared_ptr<SessionData> byWhom,unsigned playerIdWho,DenyKickPlayerReason reason)540 ServerGame::InternalDenyAskVoteKick(boost::shared_ptr<SessionData> byWhom, unsigned playerIdWho, DenyKickPlayerReason reason)
541 {
542 boost::shared_ptr<NetPacket> packet(new NetPacket);
543 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_AskKickDeniedMessage);
544 AskKickDeniedMessage *netKickDenied = packet->GetMsg()->mutable_askkickdeniedmessage();
545 netKickDenied->set_gameid(GetId());
546 netKickDenied->set_playerid(playerIdWho);
547 netKickDenied->set_kickdeniedreason(static_cast<AskKickDeniedMessage::KickDeniedReason>(reason));
548 GetLobbyThread().GetSender().Send(byWhom, packet);
549 }
550
551 void
InternalVoteKick(boost::shared_ptr<SessionData> byWhom,unsigned petitionId,KickVote vote)552 ServerGame::InternalVoteKick(boost::shared_ptr<SessionData> byWhom, unsigned petitionId, KickVote vote)
553 {
554 if (IsRunning() && byWhom->GetPlayerData()) {
555 // Check whether this is the valid petition id.
556 if (m_voteKickData && m_voteKickData->petitionId == petitionId) {
557 // Check whether the player already voted.
558 unsigned playerId = byWhom->GetPlayerData()->GetUniqueId();
559 if (find(m_voteKickData->votedPlayerIds.begin(), m_voteKickData->votedPlayerIds.end(), playerId) == m_voteKickData->votedPlayerIds.end()) {
560 m_voteKickData->votedPlayerIds.push_back(playerId);
561 if (vote == KICK_VOTE_IN_FAVOUR)
562 m_voteKickData->numVotesInFavourOfKicking++;
563 else
564 m_voteKickData->numVotesAgainstKicking++;
565 // Send update notification.
566 boost::shared_ptr<NetPacket> packet(new NetPacket);
567 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_KickPetitionUpdateMessage);
568 KickPetitionUpdateMessage *netKickUpdate = packet->GetMsg()->mutable_kickpetitionupdatemessage();
569 netKickUpdate->set_gameid(GetId());
570 netKickUpdate->set_petitionid(m_voteKickData->petitionId);
571 netKickUpdate->set_numvotesagainstkicking(m_voteKickData->numVotesAgainstKicking);
572 netKickUpdate->set_numvotesinfavourofkicking(m_voteKickData->numVotesInFavourOfKicking);
573 netKickUpdate->set_numvotesneededtokick(m_voteKickData->numVotesToKick);
574 SendToAllPlayers(packet, SessionData::Game);
575 } else
576 InternalDenyVoteKick(byWhom, petitionId, VOTE_DENIED_ALREADY_VOTED);
577 } else
578 InternalDenyVoteKick(byWhom, petitionId, VOTE_DENIED_INVALID_PETITION);
579 } else
580 InternalDenyVoteKick(byWhom, petitionId, VOTE_DENIED_INVALID_PETITION);
581 }
582
583 void
InternalDenyVoteKick(boost::shared_ptr<SessionData> byWhom,unsigned petitionId,DenyVoteReason reason)584 ServerGame::InternalDenyVoteKick(boost::shared_ptr<SessionData> byWhom, unsigned petitionId, DenyVoteReason reason)
585 {
586 boost::shared_ptr<NetPacket> packet(new NetPacket);
587 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_VoteKickReplyMessage);
588 VoteKickReplyMessage *netVoteReply = packet->GetMsg()->mutable_votekickreplymessage();
589 netVoteReply->set_gameid(GetId());
590 netVoteReply->set_petitionid(petitionId);
591 switch(reason) {
592 case VOTE_DENIED_ALREADY_VOTED :
593 netVoteReply->set_votekickreplytype(VoteKickReplyMessage::voteKickDeniedAlreadyVoted);
594 break;
595 default:
596 netVoteReply->set_votekickreplytype(VoteKickReplyMessage::voteKickDeniedInvalid);
597 break;
598 }
599 GetLobbyThread().GetSender().Send(byWhom, packet);
600 }
601
602 PlayerDataList
GetFullPlayerDataList() const603 ServerGame::GetFullPlayerDataList() const
604 {
605 PlayerDataList playerList(GetSessionManager().GetPlayerDataList());
606 boost::mutex::scoped_lock lock(m_computerPlayerListMutex);
607 copy(m_computerPlayerList.begin(), m_computerPlayerList.end(), back_inserter(playerList));
608
609 return playerList;
610 }
611
612 boost::shared_ptr<PlayerData>
GetPlayerDataByUniqueId(unsigned playerId) const613 ServerGame::GetPlayerDataByUniqueId(unsigned playerId) const
614 {
615 boost::shared_ptr<PlayerData> tmpPlayer;
616 boost::shared_ptr<SessionData> session = GetSessionManager().GetSessionByUniquePlayerId(playerId);
617 if (session) {
618 tmpPlayer = session->GetPlayerData();
619 }
620 if (!tmpPlayer) {
621 boost::mutex::scoped_lock lock(m_computerPlayerListMutex);
622 PlayerDataList::const_iterator i = m_computerPlayerList.begin();
623 PlayerDataList::const_iterator end = m_computerPlayerList.end();
624 while (i != end) {
625 if ((*i)->GetUniqueId() == playerId) {
626 tmpPlayer = *i;
627 break;
628 }
629 ++i;
630 }
631 }
632 return tmpPlayer;
633 }
634
635 PlayerIdList
GetPlayerIdList() const636 ServerGame::GetPlayerIdList() const
637 {
638 PlayerIdList idList(GetSessionManager().GetPlayerIdList(SessionData::Game));
639 boost::mutex::scoped_lock lock(m_computerPlayerListMutex);
640 PlayerDataList::const_iterator i = m_computerPlayerList.begin();
641 PlayerDataList::const_iterator end = m_computerPlayerList.end();
642 while (i != end) {
643 idList.push_back((*i)->GetUniqueId());
644 ++i;
645 }
646
647 return idList;
648 }
649
650 PlayerIdList
GetSpectatorIdList() const651 ServerGame::GetSpectatorIdList() const
652 {
653 return GetSessionManager().GetPlayerIdList(SessionData::Spectating | SessionData::SpectatorWaiting);
654 }
655
656 bool
IsPlayerConnected(const std::string & name) const657 ServerGame::IsPlayerConnected(const std::string &name) const
658 {
659 return GetSessionManager().IsPlayerConnected(name);
660 }
661
662 bool
IsPlayerConnected(unsigned playerId) const663 ServerGame::IsPlayerConnected(unsigned playerId) const
664 {
665 return GetSessionManager().IsPlayerConnected(playerId);
666 }
667
668 bool
IsClientAddressConnected(const std::string & clientAddress) const669 ServerGame::IsClientAddressConnected(const std::string &clientAddress) const
670 {
671 return GetSessionManager().IsClientAddressConnected(clientAddress);
672 }
673
674 boost::shared_ptr<PlayerInterface>
GetPlayerInterfaceFromGame(const std::string & playerName)675 ServerGame::GetPlayerInterfaceFromGame(const std::string &playerName)
676 {
677 boost::shared_ptr<PlayerInterface> tmpPlayer;
678 if (m_game) {
679 tmpPlayer = m_game->getPlayerByName(playerName);
680 }
681 return tmpPlayer;
682 }
683
684 boost::shared_ptr<PlayerInterface>
GetPlayerInterfaceFromGame(unsigned playerId)685 ServerGame::GetPlayerInterfaceFromGame(unsigned playerId)
686 {
687 boost::shared_ptr<PlayerInterface> tmpPlayer;
688 if (m_game) {
689 tmpPlayer = m_game->getPlayerByUniqueId(playerId);
690 }
691 return tmpPlayer;
692 }
693
694 bool
IsRunning() const695 ServerGame::IsRunning() const
696 {
697 return m_game.get() != NULL;
698 }
699
700 unsigned
GetAdminPlayerId() const701 ServerGame::GetAdminPlayerId() const
702 {
703 return m_adminPlayerId;
704 }
705
706 void
SetAdminPlayerId(unsigned playerId)707 ServerGame::SetAdminPlayerId(unsigned playerId)
708 {
709 m_adminPlayerId = playerId;
710 }
711
712 void
AddPlayerInvitation(unsigned playerId)713 ServerGame::AddPlayerInvitation(unsigned playerId)
714 {
715 boost::mutex::scoped_lock lock(m_playerInvitationListMutex);
716 m_playerInvitationList.push_back(playerId);
717 m_playerInvitationList.sort();
718 m_playerInvitationList.unique();
719 }
720
721 void
RemovePlayerInvitation(unsigned playerId)722 ServerGame::RemovePlayerInvitation(unsigned playerId)
723 {
724 boost::mutex::scoped_lock lock(m_playerInvitationListMutex);
725 m_playerInvitationList.remove(playerId);
726 }
727
728 bool
IsPlayerInvited(unsigned playerId) const729 ServerGame::IsPlayerInvited(unsigned playerId) const
730 {
731 bool retVal = false;
732 boost::mutex::scoped_lock lock(m_playerInvitationListMutex);
733 PlayerIdList::const_iterator pos = find(m_playerInvitationList.begin(), m_playerInvitationList.end(), playerId);
734 if (pos != m_playerInvitationList.end())
735 retVal = true;
736 return retVal;
737 }
738
739 void
SetPlayerAutoLeaveOnFinish(unsigned playerId)740 ServerGame::SetPlayerAutoLeaveOnFinish(unsigned playerId)
741 {
742 boost::mutex::scoped_lock lock(m_autoLeavePlayerListMutex);
743 m_autoLeavePlayerList.push_back(playerId);
744 }
745
746 void
AddRejoinPlayer(unsigned playerId)747 ServerGame::AddRejoinPlayer(unsigned playerId)
748 {
749 boost::mutex::scoped_lock lock(m_rejoinPlayerListMutex);
750 m_rejoinPlayerList.push_back(playerId);
751 }
752
753 PlayerIdList
GetAndResetRejoinPlayers()754 ServerGame::GetAndResetRejoinPlayers()
755 {
756 boost::mutex::scoped_lock lock(m_rejoinPlayerListMutex);
757 PlayerIdList tmpList(m_rejoinPlayerList);
758 m_rejoinPlayerList.clear();
759 return tmpList;
760 }
761
762 void
AddReactivatePlayer(unsigned playerId)763 ServerGame::AddReactivatePlayer(unsigned playerId)
764 {
765 boost::mutex::scoped_lock lock(m_reactivatePlayerListMutex);
766 m_reactivatePlayerList.push_back(playerId);
767 }
768
769 PlayerIdList
GetAndResetReactivatePlayers()770 ServerGame::GetAndResetReactivatePlayers()
771 {
772 boost::mutex::scoped_lock lock(m_reactivatePlayerListMutex);
773 PlayerIdList tmpList(m_reactivatePlayerList);
774 m_reactivatePlayerList.clear();
775 return tmpList;
776 }
777
778 void
AddNewSpectator(unsigned playerId)779 ServerGame::AddNewSpectator(unsigned playerId)
780 {
781 boost::mutex::scoped_lock lock(m_newSpectatorListMutex);
782 m_newSpectatorList.push_back(playerId);
783 }
784
785 PlayerIdList
GetAndResetNewSpectators()786 ServerGame::GetAndResetNewSpectators()
787 {
788 boost::mutex::scoped_lock lock(m_newSpectatorListMutex);
789 PlayerIdList tmpList(m_newSpectatorList);
790 m_newSpectatorList.clear();
791 return tmpList;
792 }
793
794 void
SetNameReported()795 ServerGame::SetNameReported()
796 {
797 m_isNameReported = true;
798 }
799
800 bool
IsNameReported() const801 ServerGame::IsNameReported() const
802 {
803 return m_isNameReported;
804 }
805
806 void
AddComputerPlayer(boost::shared_ptr<PlayerData> player)807 ServerGame::AddComputerPlayer(boost::shared_ptr<PlayerData> player)
808 {
809 {
810 boost::mutex::scoped_lock lock(m_computerPlayerListMutex);
811 m_computerPlayerList.push_back(player);
812 }
813 GetLobbyThread().AddComputerPlayer(player);
814 }
815
816 boost::shared_ptr<PlayerData>
RemoveComputerPlayer(unsigned playerId)817 ServerGame::RemoveComputerPlayer(unsigned playerId)
818 {
819 boost::shared_ptr<PlayerData> tmpPlayer;
820 {
821 boost::mutex::scoped_lock lock(m_computerPlayerListMutex);
822 PlayerDataList::iterator i = m_computerPlayerList.begin();
823 PlayerDataList::iterator end = m_computerPlayerList.end();
824 while (i != end) {
825 if ((*i)->GetUniqueId() == playerId) {
826 tmpPlayer = *i;
827 m_computerPlayerList.erase(i);
828 break;
829 }
830 ++i;
831 }
832 }
833 GetLobbyThread().RemoveComputerPlayer(tmpPlayer);
834 return tmpPlayer;
835 }
836
837 bool
IsComputerPlayerActive(unsigned playerId) const838 ServerGame::IsComputerPlayerActive(unsigned playerId) const
839 {
840 bool retVal = false;
841 boost::mutex::scoped_lock lock(m_computerPlayerListMutex);
842 PlayerDataList::const_iterator i = m_computerPlayerList.begin();
843 PlayerDataList::const_iterator end = m_computerPlayerList.end();
844 while (i != end) {
845 if ((*i)->GetUniqueId() == playerId)
846 retVal = true;
847 ++i;
848 }
849 return retVal;
850 }
851
852 void
ResetComputerPlayerList()853 ServerGame::ResetComputerPlayerList()
854 {
855 boost::mutex::scoped_lock lock(m_computerPlayerListMutex);
856
857 PlayerDataList::iterator i = m_computerPlayerList.begin();
858 PlayerDataList::iterator end = m_computerPlayerList.end();
859
860 while (i != end) {
861 GetLobbyThread().RemoveComputerPlayer(*i);
862 RemovePlayerData(*i, NTF_NET_REMOVED_ON_REQUEST, false);
863 ++i;
864 }
865
866 m_computerPlayerList.clear();
867 }
868
869 void
RemoveSession(boost::shared_ptr<SessionData> session,int reason)870 ServerGame::RemoveSession(boost::shared_ptr<SessionData> session, int reason)
871 {
872 if (!session)
873 throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
874
875 if (GetSessionManager().RemoveSession(session->GetId())) {
876 boost::shared_ptr<PlayerData> tmpPlayerData = session->GetPlayerData();
877 if (tmpPlayerData && !tmpPlayerData->GetName().empty()) {
878 RemovePlayerData(tmpPlayerData, reason, session->GetState() == SessionData::Spectating || session->GetState() == SessionData::SpectatorWaiting);
879 }
880 }
881 }
882
883 void
RemovePlayerData(boost::shared_ptr<PlayerData> player,int reason,bool spectateOnly)884 ServerGame::RemovePlayerData(boost::shared_ptr<PlayerData> player, int reason, bool spectateOnly)
885 {
886 if (player->IsGameAdmin()) {
887 // Find new admin for the game
888 PlayerDataList playerList(GetSessionManager().GetPlayerDataList());
889 if (!playerList.empty()) {
890 boost::shared_ptr<PlayerData> newAdmin = playerList.front();
891 SetAdminPlayerId(newAdmin->GetUniqueId());
892 newAdmin->SetGameAdmin(true);
893 // Notify game state on admin change
894 GetState().NotifyGameAdminChanged(shared_from_this());
895 // Send "Game Admin Changed" to clients.
896 boost::shared_ptr<NetPacket> adminChanged(new NetPacket);
897 adminChanged->GetMsg()->set_messagetype(PokerTHMessage::Type_GameAdminChangedMessage);
898 GameAdminChangedMessage *netGameAdmin = adminChanged->GetMsg()->mutable_gameadminchangedmessage();
899 netGameAdmin->set_gameid(GetId());
900 netGameAdmin->set_newadminplayerid(newAdmin->GetUniqueId()); // Choose next player as admin.
901 GetSessionManager().SendToAllSessions(GetLobbyThread().GetSender(), adminChanged, SessionData::Game);
902
903 GetLobbyThread().NotifyGameAdminChanged(GetId(), newAdmin->GetUniqueId());
904 }
905 }
906 // Reset player rights.
907 player->SetGameAdmin(false);
908
909 // Send "Player Left" to clients.
910 boost::shared_ptr<NetPacket> thisPlayerLeft(new NetPacket);
911 GamePlayerLeftMessage::GamePlayerLeftReason netReason = GamePlayerLeftMessage::leftError;
912 switch (reason) {
913 case NTF_NET_REMOVED_ON_REQUEST :
914 netReason = GamePlayerLeftMessage::leftOnRequest;
915 break;
916 case NTF_NET_REMOVED_KICKED :
917 netReason = GamePlayerLeftMessage::leftKicked;
918 break;
919 }
920
921 if (spectateOnly) {
922 thisPlayerLeft->GetMsg()->set_messagetype(PokerTHMessage::Type_GameSpectatorLeftMessage);
923 GameSpectatorLeftMessage *netPlayerLeft = thisPlayerLeft->GetMsg()->mutable_gamespectatorleftmessage();
924 netPlayerLeft->set_gameid(GetId());
925 netPlayerLeft->set_playerid(player->GetUniqueId());
926 netPlayerLeft->set_gamespectatorleftreason(netReason);
927 } else {
928 thisPlayerLeft->GetMsg()->set_messagetype(PokerTHMessage::Type_GamePlayerLeftMessage);
929 GamePlayerLeftMessage *netPlayerLeft = thisPlayerLeft->GetMsg()->mutable_gameplayerleftmessage();
930 netPlayerLeft->set_gameid(GetId());
931 netPlayerLeft->set_playerid(player->GetUniqueId());
932 netPlayerLeft->set_gameplayerleftreason(netReason);
933 }
934 GetSessionManager().SendToAllSessions(GetLobbyThread().GetSender(), thisPlayerLeft, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
935
936 GetState().NotifySessionRemoved(shared_from_this());
937 if (spectateOnly) {
938 GetLobbyThread().NotifySpectatorLeftGame(GetId(), player->GetUniqueId());
939 } else {
940 GetLobbyThread().NotifyPlayerLeftGame(GetId(), player->GetUniqueId());
941 }
942 }
943
944 void
SessionError(boost::shared_ptr<SessionData> session,int errorCode)945 ServerGame::SessionError(boost::shared_ptr<SessionData> session, int errorCode)
946 {
947 if (!session)
948 throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
949 RemoveSession(session, NTF_NET_INTERNAL);
950 GetLobbyThread().SessionError(session, errorCode);
951 }
952
953 void
MoveSessionToLobby(boost::shared_ptr<SessionData> session,int reason)954 ServerGame::MoveSessionToLobby(boost::shared_ptr<SessionData> session, int reason)
955 {
956 RemoveSession(session, reason);
957 // Reset ready flag - just in case it is set, player may leave at any time.
958 session->ResetReadyFlag();
959 GetLobbyThread().ReAddSession(session, reason, GetId());
960 }
961
962 void
RemoveDisconnectedPlayers()963 ServerGame::RemoveDisconnectedPlayers()
964 {
965 // This should only be called between hands.
966 if (m_game) {
967 PlayerList tmpList(m_game->getSeatsList());
968 PlayerListIterator i = tmpList->begin();
969 PlayerListIterator end = tmpList->end();
970 while (i != end) {
971 boost::shared_ptr<PlayerInterface> tmpPlayer = *i;
972 if ((tmpPlayer->getMyType() == PLAYER_TYPE_HUMAN && !GetSessionManager().IsPlayerConnected(tmpPlayer->getMyUniqueID()))
973 || (tmpPlayer->getMyType() == PLAYER_TYPE_COMPUTER && !IsComputerPlayerActive(tmpPlayer->getMyUniqueID()))) {
974 // Setting player cash to 0 will deactivate the player.
975 // The player should only be deactivated if rejoin is not possible.
976 if (tmpPlayer->isKicked() || tmpPlayer->getMyGuid().empty()) {
977 tmpPlayer->setMyCash(0);
978 tmpPlayer->setMyGuid("");
979 }
980 tmpPlayer->setIsSessionActive(false);
981 }
982 ++i;
983 }
984 }
985 }
986
987 int
GetCurNumberOfPlayers() const988 ServerGame::GetCurNumberOfPlayers() const
989 {
990 return (int)GetFullPlayerDataList().size();
991 }
992
993 void
AssignPlayerNumbers(PlayerDataList & playerList)994 ServerGame::AssignPlayerNumbers(PlayerDataList &playerList)
995 {
996 int playerNumber = 0;
997
998 PlayerDataList::iterator player_i = playerList.begin();
999 PlayerDataList::iterator player_end = playerList.end();
1000
1001 while (player_i != player_end) {
1002 (*player_i)->SetNumber(playerNumber);
1003 ++playerNumber;
1004 ++player_i;
1005 }
1006 }
1007
1008 bool
IsValidPlayer(unsigned playerId) const1009 ServerGame::IsValidPlayer(unsigned playerId) const
1010 {
1011 bool retVal = false;
1012 const PlayerIdList list(GetPlayerIdList());
1013 if (find(list.begin(), list.end(), playerId) != list.end())
1014 retVal = true;
1015 return retVal;
1016 }
1017
1018 void
AddReportedAvatar(unsigned playerId)1019 ServerGame::AddReportedAvatar(unsigned playerId)
1020 {
1021 m_reportedAvatarList.push_back(playerId);
1022 }
1023
1024 bool
IsAvatarReported(unsigned playerId) const1025 ServerGame::IsAvatarReported(unsigned playerId) const
1026 {
1027 bool retVal = false;
1028 PlayerIdList::const_iterator pos = find(m_reportedAvatarList.begin(), m_reportedAvatarList.end(), playerId);
1029 if (pos != m_reportedAvatarList.end())
1030 retVal = true;
1031 return retVal;
1032 }
1033
1034 SessionManager &
GetSessionManager()1035 ServerGame::GetSessionManager()
1036 {
1037 return m_sessionManager;
1038 }
1039
1040 const SessionManager &
GetSessionManager() const1041 ServerGame::GetSessionManager() const
1042 {
1043 return m_sessionManager;
1044 }
1045
1046 ServerDBInterface &
GetDatabase()1047 ServerGame::GetDatabase()
1048 {
1049 assert(m_database);
1050 return *m_database;
1051 }
1052
1053 ServerLobbyThread &
GetLobbyThread()1054 ServerGame::GetLobbyThread()
1055 {
1056 assert(m_lobbyThread);
1057 return *m_lobbyThread;
1058 }
1059
1060 ServerCallback &
GetCallback()1061 ServerGame::GetCallback()
1062 {
1063 return m_gui;
1064 }
1065
1066 ServerGameState &
GetState()1067 ServerGame::GetState()
1068 {
1069 assert(m_curState);
1070 return *m_curState;
1071 }
1072
1073 void
SetState(ServerGameState & newState)1074 ServerGame::SetState(ServerGameState &newState)
1075 {
1076 if (m_curState)
1077 m_curState->Exit(shared_from_this());
1078 m_curState = &newState;
1079 m_curState->Enter(shared_from_this());
1080 }
1081
1082 boost::asio::steady_timer &
GetStateTimer1()1083 ServerGame::GetStateTimer1()
1084 {
1085 return m_stateTimer1;
1086 }
1087
1088 boost::asio::steady_timer &
GetStateTimer2()1089 ServerGame::GetStateTimer2()
1090 {
1091 return m_stateTimer2;
1092 }
1093
1094 Game &
GetGame()1095 ServerGame::GetGame()
1096 {
1097 assert(m_game.get());
1098 return *m_game;
1099 }
1100
1101 const Game &
GetGame() const1102 ServerGame::GetGame() const
1103 {
1104 assert(m_game.get());
1105 return *m_game;
1106 }
1107
1108 const GameData &
GetGameData() const1109 ServerGame::GetGameData() const
1110 {
1111 return m_gameData;
1112 }
1113
1114 const StartData &
GetStartData() const1115 ServerGame::GetStartData() const
1116 {
1117 return m_startData;
1118 }
1119
1120 void
SetStartData(const StartData & startData)1121 ServerGame::SetStartData(const StartData &startData)
1122 {
1123 m_startData = startData;
1124 }
1125
1126 bool
IsPasswordProtected() const1127 ServerGame::IsPasswordProtected() const
1128 {
1129 return !m_password.empty();
1130 }
1131
1132 bool
CheckPassword(const string & password) const1133 ServerGame::CheckPassword(const string &password) const
1134 {
1135 return (password == m_password);
1136 }
1137
1138 bool
CheckSettings(const GameData & data,const string & password,ServerMode mode)1139 ServerGame::CheckSettings(const GameData &data, const string &password, ServerMode mode)
1140 {
1141 bool retVal = true;
1142 if (mode != SERVER_MODE_LAN) {
1143 if (data.playerActionTimeoutSec < 5) {
1144 retVal = false;
1145 }
1146 }
1147 if (data.gameType == GAME_TYPE_RANKING) {
1148 if ((data.startMoney != RANKING_GAME_START_CASH)
1149 || (data.maxNumberOfPlayers != RANKING_GAME_NUMBER_OF_PLAYERS)
1150 || (data.firstSmallBlind != RANKING_GAME_START_SBLIND)
1151 || (data.raiseIntervalMode != RAISE_ON_HANDNUMBER)
1152 || (data.raiseMode != DOUBLE_BLINDS)
1153 || (data.raiseSmallBlindEveryHandsValue != RANKING_GAME_RAISE_EVERY_HAND)
1154 || (!password.empty())
1155 || (!data.allowSpectators)) {
1156 retVal = false;
1157 }
1158 }
1159 return retVal;
1160 }
1161
1162 GuiInterface &
GetGui()1163 ServerGame::GetGui()
1164 {
1165 return m_gui;
1166 }
1167
1168 unsigned
GetNextGameNum()1169 ServerGame::GetNextGameNum()
1170 {
1171 return m_gameNum++;
1172 }
1173
1174 void
AddPlayerToNumJoinsPerPlayer(const std::string & playerName)1175 ServerGame::AddPlayerToNumJoinsPerPlayer(const std::string &playerName)
1176 {
1177 NumJoinsPerPlayerMap::iterator pos = m_numJoinsPerPlayer.find(playerName);
1178 if (pos != m_numJoinsPerPlayer.end()) {
1179 pos->second++;
1180 } else {
1181 m_numJoinsPerPlayer[playerName] = 1;
1182 }
1183 }
1184
1185 int
GetNumJoinsPerPlayer(const std::string & playerName)1186 ServerGame::GetNumJoinsPerPlayer(const std::string &playerName)
1187 {
1188 int num = 0;
1189 NumJoinsPerPlayerMap::const_iterator pos = m_numJoinsPerPlayer.find(playerName);
1190 if (pos != m_numJoinsPerPlayer.end()) {
1191 num = pos->second;
1192 }
1193 return num;
1194 }
1195