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