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 <net/clientstate.h>
33 #include <net/clientthread.h>
34 #include <net/clientcontext.h>
35 #include <net/senderhelper.h>
36 #include <net/netpacket.h>
37 #include <net/clientexception.h>
38 #include <net/socket_helper.h>
39 #include <net/socket_msg.h>
40 #include <net/downloadhelper.h>
41 #include <core/avatarmanager.h>
42 #include <core/crypthelper.h>
43 #include <qttoolsinterface.h>
44
45 #include <game.h>
46 #include <playerinterface.h>
47
48 #include <tinyxml.h>
49 #include <boost/bind.hpp>
50 #include <boost/foreach.hpp>
51 #include <boost/iostreams/filtering_streambuf.hpp>
52 #include <boost/iostreams/copy.hpp>
53 #include <boost/iostreams/filter/zlib.hpp>
54 #include <boost/filesystem.hpp>
55
56 #include <iostream>
57 #include <fstream>
58 #include <sstream>
59
60 using namespace std;
61 using namespace boost::filesystem;
62
63 #ifdef BOOST_ASIO_HAS_STD_CHRONO
64 using namespace std::chrono;
65 #else
66 using namespace boost::chrono;
67 #endif
68
69 #define CLIENT_WAIT_TIMEOUT_MSEC 50
70 #define CLIENT_CONNECT_TIMEOUT_SEC 10
71
72
~ClientState()73 ClientState::~ClientState()
74 {
75 }
76
77 //-----------------------------------------------------------------------------
78
79 ClientStateInit &
Instance()80 ClientStateInit::Instance()
81 {
82 static ClientStateInit state;
83 return state;
84 }
85
ClientStateInit()86 ClientStateInit::ClientStateInit()
87 {
88 }
89
~ClientStateInit()90 ClientStateInit::~ClientStateInit()
91 {
92 }
93
94 void
Enter(boost::shared_ptr<ClientThread> client)95 ClientStateInit::Enter(boost::shared_ptr<ClientThread> client)
96 {
97 ClientContext &context = client->GetContext();
98
99 if (context.GetServerAddr().empty())
100 throw ClientException(__FILE__, __LINE__, ERR_SOCK_SERVERADDR_NOT_SET, 0);
101
102 if (context.GetServerPort() < 1024)
103 throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_PORT, 0);
104
105 client->CreateContextSession();
106 client->GetCallback().SignalNetClientConnect(MSG_SOCK_INIT_DONE);
107
108 if (context.GetUseServerList())
109 client->SetState(ClientStateStartServerListDownload::Instance());
110 else
111 client->SetState(ClientStateStartResolve::Instance());
112 }
113
114 void
Exit(boost::shared_ptr<ClientThread>)115 ClientStateInit::Exit(boost::shared_ptr<ClientThread> /*client*/)
116 {
117 // Nothing to do.
118 }
119
120 //-----------------------------------------------------------------------------
121
122 ClientStateStartResolve &
Instance()123 ClientStateStartResolve::Instance()
124 {
125 static ClientStateStartResolve state;
126 return state;
127 }
128
ClientStateStartResolve()129 ClientStateStartResolve::ClientStateStartResolve()
130 {
131 }
132
~ClientStateStartResolve()133 ClientStateStartResolve::~ClientStateStartResolve()
134 {
135 }
136
137 void
Enter(boost::shared_ptr<ClientThread> client)138 ClientStateStartResolve::Enter(boost::shared_ptr<ClientThread> client)
139 {
140 ClientContext &context = client->GetContext();
141 ostringstream portStr;
142 portStr << context.GetServerPort();
143 boost::asio::ip::tcp::resolver::query q(context.GetServerAddr(), portStr.str());
144
145 context.GetResolver()->async_resolve(
146 q,
147 boost::bind(&ClientStateStartResolve::HandleResolve,
148 this,
149 boost::asio::placeholders::error,
150 boost::asio::placeholders::iterator,
151 client));
152 }
153
154 void
Exit(boost::shared_ptr<ClientThread> client)155 ClientStateStartResolve::Exit(boost::shared_ptr<ClientThread> client)
156 {
157 client->GetContext().GetResolver()->cancel();
158 }
159
160 void
HandleResolve(const boost::system::error_code & ec,boost::asio::ip::tcp::resolver::iterator endpoint_iterator,boost::shared_ptr<ClientThread> client)161 ClientStateStartResolve::HandleResolve(const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator endpoint_iterator,
162 boost::shared_ptr<ClientThread> client)
163 {
164 if (!ec && &client->GetState() == this) {
165 client->GetCallback().SignalNetClientConnect(MSG_SOCK_RESOLVE_DONE);
166 // Use the first resolver result.
167 ClientStateStartConnect::Instance().SetRemoteEndpoint(endpoint_iterator);
168 client->SetState(ClientStateStartConnect::Instance());
169 } else {
170 if (ec != boost::asio::error::operation_aborted)
171 throw ClientException(__FILE__, __LINE__, ERR_SOCK_RESOLVE_FAILED, 0);
172 }
173 }
174
175 //-----------------------------------------------------------------------------
176
177 ClientStateStartServerListDownload &
Instance()178 ClientStateStartServerListDownload::Instance()
179 {
180 static ClientStateStartServerListDownload state;
181 return state;
182 }
183
ClientStateStartServerListDownload()184 ClientStateStartServerListDownload::ClientStateStartServerListDownload()
185 {
186 }
187
~ClientStateStartServerListDownload()188 ClientStateStartServerListDownload::~ClientStateStartServerListDownload()
189 {
190 }
191
192 void
Enter(boost::shared_ptr<ClientThread> client)193 ClientStateStartServerListDownload::Enter(boost::shared_ptr<ClientThread> client)
194 {
195 path tmpServerListPath(client->GetCacheServerListFileName());
196 if (tmpServerListPath.empty())
197 throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_URL, 0);
198
199 if (exists(tmpServerListPath)) {
200 // Download the current server list once a day.
201 // If the previous file is older than one day, delete it.
202 // Also delete the file if it is empty.
203 if (file_size(tmpServerListPath) == 0 || (last_write_time(tmpServerListPath) + 86400 < time(NULL))) {
204 remove(tmpServerListPath);
205 }
206 }
207
208 if (exists(tmpServerListPath)) {
209 // Use the existing server list.
210 client->SetState(ClientStateReadingServerList::Instance());
211 } else {
212 // Download the server list.
213 boost::shared_ptr<DownloadHelper> downloader(new DownloadHelper);
214 downloader->Init(client->GetContext().GetServerListUrl(), tmpServerListPath.directory_string());
215 ClientStateDownloadingServerList::Instance().SetDownloadHelper(downloader);
216 client->SetState(ClientStateDownloadingServerList::Instance());
217 }
218 }
219
220 void
Exit(boost::shared_ptr<ClientThread>)221 ClientStateStartServerListDownload::Exit(boost::shared_ptr<ClientThread> /*client*/)
222 {
223 // Nothing to do.
224 }
225
226 //-----------------------------------------------------------------------------
227
228 ClientStateDownloadingServerList &
Instance()229 ClientStateDownloadingServerList::Instance()
230 {
231 static ClientStateDownloadingServerList state;
232 return state;
233 }
234
ClientStateDownloadingServerList()235 ClientStateDownloadingServerList::ClientStateDownloadingServerList()
236 {
237 }
238
~ClientStateDownloadingServerList()239 ClientStateDownloadingServerList::~ClientStateDownloadingServerList()
240 {
241 }
242
243 void
Enter(boost::shared_ptr<ClientThread> client)244 ClientStateDownloadingServerList::Enter(boost::shared_ptr<ClientThread> client)
245 {
246 client->GetStateTimer().expires_from_now(
247 milliseconds(CLIENT_WAIT_TIMEOUT_MSEC));
248 client->GetStateTimer().async_wait(
249 boost::bind(
250 &ClientStateDownloadingServerList::TimerLoop, this, boost::asio::placeholders::error, client));
251 }
252
253 void
Exit(boost::shared_ptr<ClientThread> client)254 ClientStateDownloadingServerList::Exit(boost::shared_ptr<ClientThread> client)
255 {
256 client->GetStateTimer().cancel();
257 }
258
259 void
SetDownloadHelper(boost::shared_ptr<DownloadHelper> helper)260 ClientStateDownloadingServerList::SetDownloadHelper(boost::shared_ptr<DownloadHelper> helper)
261 {
262 m_downloadHelper = helper;
263 }
264
265 void
TimerLoop(const boost::system::error_code & ec,boost::shared_ptr<ClientThread> client)266 ClientStateDownloadingServerList::TimerLoop(const boost::system::error_code& ec, boost::shared_ptr<ClientThread> client)
267 {
268 if (!ec && &client->GetState() == this) {
269 if (m_downloadHelper->Process()) {
270 m_downloadHelper.reset();
271 client->SetState(ClientStateReadingServerList::Instance());
272 } else {
273 client->GetStateTimer().expires_from_now(
274 milliseconds(CLIENT_WAIT_TIMEOUT_MSEC));
275 client->GetStateTimer().async_wait(
276 boost::bind(
277 &ClientStateDownloadingServerList::TimerLoop, this, boost::asio::placeholders::error, client));
278 }
279 }
280 }
281
282 //-----------------------------------------------------------------------------
283
284 ClientStateReadingServerList &
Instance()285 ClientStateReadingServerList::Instance()
286 {
287 static ClientStateReadingServerList state;
288 return state;
289 }
290
ClientStateReadingServerList()291 ClientStateReadingServerList::ClientStateReadingServerList()
292 {
293 }
294
~ClientStateReadingServerList()295 ClientStateReadingServerList::~ClientStateReadingServerList()
296 {
297 }
298
299 void
Enter(boost::shared_ptr<ClientThread> client)300 ClientStateReadingServerList::Enter(boost::shared_ptr<ClientThread> client)
301 {
302 ClientContext &context = client->GetContext();
303 path zippedServerListPath(context.GetCacheDir());
304 zippedServerListPath /= context.GetServerListUrl().substr(context.GetServerListUrl().find_last_of('/') + 1);
305 path xmlServerListPath;
306 if (extension(zippedServerListPath) == ".z") {
307 xmlServerListPath = change_extension(zippedServerListPath, "");
308
309 // Unzip the file using zlib.
310 try {
311 std::ifstream inFile(zippedServerListPath.directory_string().c_str(), ios_base::in | ios_base::binary);
312 std::ofstream outFile(xmlServerListPath.directory_string().c_str(), ios_base::out | ios_base::trunc);
313 boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
314 in.push(boost::iostreams::zlib_decompressor());
315 in.push(inFile);
316 boost::iostreams::copy(in, outFile);
317 } catch (...) {
318 throw ClientException(__FILE__, __LINE__, ERR_SOCK_UNZIP_FAILED, 0);
319 }
320 } else
321 xmlServerListPath = zippedServerListPath;
322
323 // Parse the server address.
324 TiXmlDocument doc(xmlServerListPath.directory_string());
325
326 if (doc.LoadFile()) {
327 client->ClearServerInfoMap();
328 int serverCount = 0;
329 unsigned lastServerInfoId = 0;
330 TiXmlHandle docHandle(&doc);
331 const TiXmlElement *nextServer = docHandle.FirstChild("ServerList" ).FirstChild("Server").ToElement();
332 while (nextServer) {
333 ServerInfo serverInfo;
334 {
335 int tmpId;
336 nextServer->QueryIntAttribute("id", &tmpId);
337 serverInfo.id = (unsigned)tmpId;
338 }
339 const TiXmlNode *nameNode = nextServer->FirstChild("Name");
340 const TiXmlNode *sponsorNode = nextServer->FirstChild("Sponsor");
341 const TiXmlNode *countryNode = nextServer->FirstChild("Country");
342 const TiXmlNode *addr4Node = nextServer->FirstChild("IPv4Address");
343 const TiXmlNode *addr6Node = nextServer->FirstChild("IPv6Address");
344 const TiXmlNode *sctpNode = nextServer->FirstChild("SCTP");
345 const TiXmlNode *portNode = nextServer->FirstChild("ProtobufPort");
346
347 // IPv6 support for avatar servers depends on this address and on libcurl.
348 const TiXmlNode *avatarNode = nextServer->FirstChild("AvatarServerAddress");
349
350 if (!nameNode || !nameNode->ToElement() || !addr4Node || !addr4Node->ToElement()
351 || !addr6Node || !addr6Node->ToElement() || !portNode || !portNode->ToElement())
352 throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_XML, 0);
353
354 serverInfo.name = nameNode->ToElement()->Attribute("value");
355 serverInfo.ipv4addr = addr4Node->ToElement()->Attribute("value");
356 serverInfo.ipv6addr = addr6Node->ToElement()->Attribute("value");
357 portNode->ToElement()->QueryIntAttribute("value", &serverInfo.port);
358
359 // Optional parameters:
360 if (sponsorNode && sponsorNode->ToElement())
361 serverInfo.sponsor = sponsorNode->ToElement()->Attribute("value");
362 if (countryNode && countryNode->ToElement())
363 serverInfo.country = countryNode->ToElement()->Attribute("value");
364 if (sctpNode && sctpNode->ToElement()) {
365 int tmpSctp;
366 sctpNode->ToElement()->QueryIntAttribute("value", &tmpSctp);
367 serverInfo.supportsSctp = tmpSctp == 1 ? true : false;
368 }
369 if (avatarNode && avatarNode->ToElement())
370 serverInfo.avatarServerAddr = avatarNode->ToElement()->Attribute("value");
371
372 client->AddServerInfo(serverInfo.id, serverInfo);
373 nextServer = nextServer->NextSiblingElement();
374 lastServerInfoId = serverInfo.id;
375 serverCount++;
376 }
377
378 if (serverCount == 1) {
379 client->UseServer(lastServerInfoId);
380 client->GetCallback().SignalNetClientConnect(MSG_SOCK_SERVER_LIST_DONE);
381 client->SetState(ClientStateStartResolve::Instance());
382 } else if (serverCount > 1) {
383 client->GetCallback().SignalNetClientServerListShow();
384 client->SetState(ClientStateWaitChooseServer::Instance());
385 } else
386 throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_XML, 0);
387 } else
388 throw ClientException(__FILE__, __LINE__, ERR_SOCK_INVALID_SERVERLIST_XML, 0);
389 }
390
391 void
Exit(boost::shared_ptr<ClientThread>)392 ClientStateReadingServerList::Exit(boost::shared_ptr<ClientThread> /*client*/)
393 {
394 // Nothing to do.
395 }
396
397 //-----------------------------------------------------------------------------
398
399 ClientStateWaitChooseServer &
Instance()400 ClientStateWaitChooseServer::Instance()
401 {
402 static ClientStateWaitChooseServer state;
403 return state;
404 }
405
ClientStateWaitChooseServer()406 ClientStateWaitChooseServer::ClientStateWaitChooseServer()
407 {
408 }
409
~ClientStateWaitChooseServer()410 ClientStateWaitChooseServer::~ClientStateWaitChooseServer()
411 {
412 }
413
414 void
Enter(boost::shared_ptr<ClientThread> client)415 ClientStateWaitChooseServer::Enter(boost::shared_ptr<ClientThread> client)
416 {
417 client->GetStateTimer().expires_from_now(
418 milliseconds(CLIENT_WAIT_TIMEOUT_MSEC));
419 client->GetStateTimer().async_wait(
420 boost::bind(
421 &ClientStateWaitChooseServer::TimerLoop, this, boost::asio::placeholders::error, client));
422 }
423
424 void
Exit(boost::shared_ptr<ClientThread> client)425 ClientStateWaitChooseServer::Exit(boost::shared_ptr<ClientThread> client)
426 {
427 client->GetStateTimer().cancel();
428 }
429
430 void
TimerLoop(const boost::system::error_code & ec,boost::shared_ptr<ClientThread> client)431 ClientStateWaitChooseServer::TimerLoop(const boost::system::error_code& ec, boost::shared_ptr<ClientThread> client)
432 {
433 if (!ec && &client->GetState() == this) {
434 unsigned serverId;
435 if (client->GetSelectedServer(serverId)) {
436 client->UseServer(serverId);
437 client->GetCallback().SignalNetClientConnect(MSG_SOCK_SERVER_LIST_DONE);
438 client->SetState(ClientStateStartResolve::Instance());
439 } else {
440 client->GetStateTimer().expires_from_now(
441 milliseconds(CLIENT_WAIT_TIMEOUT_MSEC));
442 client->GetStateTimer().async_wait(
443 boost::bind(
444 &ClientStateWaitChooseServer::TimerLoop, this, boost::asio::placeholders::error, client));
445 }
446 }
447 }
448
449 //-----------------------------------------------------------------------------
450
451 ClientStateStartConnect &
Instance()452 ClientStateStartConnect::Instance()
453 {
454 static ClientStateStartConnect state;
455 return state;
456 }
457
ClientStateStartConnect()458 ClientStateStartConnect::ClientStateStartConnect()
459 {
460 }
461
~ClientStateStartConnect()462 ClientStateStartConnect::~ClientStateStartConnect()
463 {
464 }
465
466 void
Enter(boost::shared_ptr<ClientThread> client)467 ClientStateStartConnect::Enter(boost::shared_ptr<ClientThread> client)
468 {
469 client->GetStateTimer().expires_from_now(
470 seconds(CLIENT_CONNECT_TIMEOUT_SEC));
471 client->GetStateTimer().async_wait(
472 boost::bind(
473 &ClientStateStartConnect::TimerTimeout, this, boost::asio::placeholders::error, client));
474
475 boost::asio::ip::tcp::endpoint endpoint = *m_remoteEndpointIterator;
476 client->GetContext().GetSessionData()->GetAsioSocket()->async_connect(
477 endpoint,
478 boost::bind(&ClientStateStartConnect::HandleConnect,
479 this,
480 boost::asio::placeholders::error,
481 ++m_remoteEndpointIterator,
482 client));
483 }
484
485 void
Exit(boost::shared_ptr<ClientThread> client)486 ClientStateStartConnect::Exit(boost::shared_ptr<ClientThread> client)
487 {
488 client->GetStateTimer().cancel();
489 }
490
491 void
SetRemoteEndpoint(boost::asio::ip::tcp::resolver::iterator endpointIterator)492 ClientStateStartConnect::SetRemoteEndpoint(boost::asio::ip::tcp::resolver::iterator endpointIterator)
493 {
494 m_remoteEndpointIterator = endpointIterator;
495 }
496
497 void
HandleConnect(const boost::system::error_code & ec,boost::asio::ip::tcp::resolver::iterator endpoint_iterator,boost::shared_ptr<ClientThread> client)498 ClientStateStartConnect::HandleConnect(const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator endpoint_iterator,
499 boost::shared_ptr<ClientThread> client)
500 {
501 if (&client->GetState() == this) {
502 if (!ec) {
503 client->GetCallback().SignalNetClientConnect(MSG_SOCK_CONNECT_DONE);
504 client->SetState(ClientStateStartSession::Instance());
505 } else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) {
506 // Try next resolve entry.
507 ClientContext &context = client->GetContext();
508 boost::system::error_code ec;
509 context.GetSessionData()->GetAsioSocket()->close(ec);
510 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
511 context.GetSessionData()->GetAsioSocket()->async_connect(
512 endpoint,
513 boost::bind(&ClientStateStartConnect::HandleConnect,
514 this,
515 boost::asio::placeholders::error,
516 ++m_remoteEndpointIterator,
517 client));
518 } else {
519 if (ec != boost::asio::error::operation_aborted) {
520 if (client->GetContext().GetAddrFamily() == AF_INET6) {
521 throw ClientException(__FILE__, __LINE__, ERR_SOCK_CONNECT_IPV6_FAILED, ec.value());
522 } else {
523 throw ClientException(__FILE__, __LINE__, ERR_SOCK_CONNECT_FAILED, ec.value());
524 }
525 }
526 }
527 }
528 }
529
530 void
TimerTimeout(const boost::system::error_code & ec,boost::shared_ptr<ClientThread> client)531 ClientStateStartConnect::TimerTimeout(const boost::system::error_code& ec, boost::shared_ptr<ClientThread> client)
532 {
533 if (!ec && &client->GetState() == this) {
534 boost::system::error_code ec;
535 client->GetContext().GetSessionData()->GetAsioSocket()->close(ec);
536 if (client->GetContext().GetAddrFamily() == AF_INET6) {
537 throw ClientException(__FILE__, __LINE__, ERR_SOCK_CONNECT_IPV6_TIMEOUT, 0);
538 } else {
539 throw ClientException(__FILE__, __LINE__, ERR_SOCK_CONNECT_TIMEOUT, 0);
540 }
541 }
542 }
543
544 //-----------------------------------------------------------------------------
545
AbstractClientStateReceiving()546 AbstractClientStateReceiving::AbstractClientStateReceiving()
547 {
548 }
549
~AbstractClientStateReceiving()550 AbstractClientStateReceiving::~AbstractClientStateReceiving()
551 {
552 }
553
554 void
HandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)555 AbstractClientStateReceiving::HandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
556 {
557 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_PlayerInfoReplyMessage) {
558 const PlayerInfoReplyMessage &infoReply = tmpPacket->GetMsg()->playerinforeplymessage();
559 unsigned playerId = infoReply.playerid();
560 if (infoReply.has_playerinfodata()) {
561 PlayerInfo tmpInfo;
562 const PlayerInfoReplyMessage::PlayerInfoData &netInfo = infoReply.playerinfodata();
563 tmpInfo.playerName = netInfo.playername();
564 tmpInfo.ptype = netInfo.ishuman() ? PLAYER_TYPE_HUMAN : PLAYER_TYPE_COMPUTER;
565 tmpInfo.isGuest = netInfo.playerrights() == netPlayerRightsGuest;
566 tmpInfo.isAdmin = netInfo.playerrights() == netPlayerRightsAdmin;
567 if (netInfo.has_countrycode()) {
568 tmpInfo.countryCode = netInfo.countrycode();
569 }
570 if (netInfo.has_avatardata()) {
571 tmpInfo.hasAvatar = true;
572 memcpy(tmpInfo.avatar.GetData(), netInfo.avatardata().avatarhash().data(), MD5_DATA_SIZE);
573 tmpInfo.avatarType = static_cast<AvatarFileType>(netInfo.avatardata().avatartype());
574 }
575 client->SetPlayerInfo(
576 playerId,
577 tmpInfo);
578 } else {
579 client->SetUnknownPlayer(playerId);
580 }
581 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_RemovedFromGameMessage) {
582 const RemovedFromGameMessage &netRemoved = tmpPacket->GetMsg()->removedfromgamemessage();
583
584 client->ClearPlayerDataList();
585 // Resubscribe Lobby messages.
586 client->ResubscribeLobbyMsg();
587 // Show Lobby.
588 client->GetCallback().SignalNetClientWaitDialog();
589 int removeReason;
590 switch (netRemoved.removedfromgamereason()) {
591 case RemovedFromGameMessage::kickedFromGame :
592 removeReason = NTF_NET_REMOVED_KICKED;
593 break;
594 case RemovedFromGameMessage::gameIsFull :
595 removeReason = NTF_NET_REMOVED_GAME_FULL;
596 break;
597 case RemovedFromGameMessage::gameIsRunning :
598 removeReason = NTF_NET_REMOVED_ALREADY_RUNNING;
599 break;
600 case RemovedFromGameMessage::gameTimeout :
601 removeReason = NTF_NET_REMOVED_TIMEOUT;
602 break;
603 case RemovedFromGameMessage::removedStartFailed :
604 removeReason = NTF_NET_REMOVED_START_FAILED;
605 break;
606 case RemovedFromGameMessage::gameClosed :
607 removeReason = NTF_NET_REMOVED_GAME_CLOSED;
608 break;
609 default :
610 removeReason = NTF_NET_REMOVED_ON_REQUEST;
611 break;
612 }
613 client->GetCallback().SignalNetClientRemovedFromGame(removeReason);
614 client->SetState(ClientStateWaitJoin::Instance());
615 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GamePlayerLeftMessage) {
616 // A player left the game.
617 const GamePlayerLeftMessage &netLeft = tmpPacket->GetMsg()->gameplayerleftmessage();
618
619 if (client->GetGame()) {
620 boost::shared_ptr<PlayerInterface> tmpPlayer = client->GetGame()->getPlayerByUniqueId(netLeft.playerid());
621 if (tmpPlayer) {
622 tmpPlayer->setIsKicked(netLeft.gameplayerleftreason() == GamePlayerLeftMessage::leftKicked);
623 }
624 }
625 // Signal to GUI and remove from data list.
626 int removeReason;
627 switch (netLeft.gameplayerleftreason()) {
628 case GamePlayerLeftMessage::leftKicked :
629 removeReason = NTF_NET_REMOVED_KICKED;
630 break;
631 default :
632 removeReason = NTF_NET_REMOVED_ON_REQUEST;
633 break;
634 }
635 client->RemovePlayerData(netLeft.playerid(), removeReason);
636 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameAdminChangedMessage) {
637 // New admin for the game.
638 const GameAdminChangedMessage &netChanged = tmpPacket->GetMsg()->gameadminchangedmessage();
639
640 // Set new game admin and signal to GUI.
641 client->SetNewGameAdmin(netChanged.newadminplayerid());
642 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GamePlayerJoinedMessage) {
643 // Another player joined the network game.
644 const GamePlayerJoinedMessage &netPlayerJoined = tmpPacket->GetMsg()->gameplayerjoinedmessage();
645
646 boost::shared_ptr<PlayerData> playerData = client->CreatePlayerData(netPlayerJoined.playerid(), netPlayerJoined.isgameadmin());
647 client->AddPlayerData(playerData);
648 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameSpectatorJoinedMessage) {
649 // Another spectator joined the network game.
650 const GameSpectatorJoinedMessage &netSpectatorJoined = tmpPacket->GetMsg()->gamespectatorjoinedmessage();
651 // Request player info if needed.
652 PlayerInfo info;
653 if (!client->GetCachedPlayerInfo(netSpectatorJoined.playerid(), info)) {
654 client->RequestPlayerInfo(netSpectatorJoined.playerid());
655 }
656 client->ModifyGameInfoAddSpectatorDuringGame(netSpectatorJoined.playerid());
657 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameSpectatorLeftMessage) {
658 // A spectator left the network game.
659 const GameSpectatorLeftMessage &netSpectatorLeft = tmpPacket->GetMsg()->gamespectatorleftmessage();
660 // Signal to GUI and remove from data list.
661 int removeReason;
662 switch (netSpectatorLeft.gamespectatorleftreason()) {
663 case GamePlayerLeftMessage::leftKicked :
664 removeReason = NTF_NET_REMOVED_KICKED;
665 break;
666 default :
667 removeReason = NTF_NET_REMOVED_ON_REQUEST;
668 break;
669 }
670 client->ModifyGameInfoRemoveSpectatorDuringGame(netSpectatorLeft.playerid(), removeReason);
671 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_TimeoutWarningMessage) {
672 const TimeoutWarningMessage &tmpTimeout = tmpPacket->GetMsg()->timeoutwarningmessage();
673 client->GetCallback().SignalNetClientShowTimeoutDialog((NetTimeoutReason)tmpTimeout.timeoutreason(), tmpTimeout.remainingseconds());
674 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_ChatMessage) {
675 // Chat message - display it in the GUI.
676 const ChatMessage &netMessage = tmpPacket->GetMsg()->chatmessage();
677
678 string playerName;
679 if (netMessage.chattype() == ChatMessage::chatTypeBroadcast) {
680 client->GetCallback().SignalNetClientGameChatMsg("(global notice)", netMessage.chattext());
681 client->GetCallback().SignalNetClientLobbyChatMsg("(global notice)", netMessage.chattext());
682 } else if (netMessage.chattype() == ChatMessage::chatTypeBot) {
683 client->GetCallback().SignalNetClientGameChatMsg("(chat bot)", netMessage.chattext());
684 client->GetCallback().SignalNetClientLobbyChatMsg("(chat bot)", netMessage.chattext());
685 } else if (netMessage.chattype() == ChatMessage::chatTypeGame) {
686 unsigned playerId = netMessage.playerid();
687 boost::shared_ptr<PlayerData> tmpPlayer = client->GetPlayerDataByUniqueId(playerId);
688 if (tmpPlayer.get())
689 playerName = tmpPlayer->GetName();
690 if (!playerName.empty())
691 client->GetCallback().SignalNetClientGameChatMsg(playerName, netMessage.chattext());
692 } else if (netMessage.chattype() == ChatMessage::chatTypeLobby) {
693 unsigned playerId = netMessage.playerid();
694 PlayerInfo info;
695 if (client->GetCachedPlayerInfo(playerId, info))
696 client->GetCallback().SignalNetClientLobbyChatMsg(info.playerName, netMessage.chattext());
697 } else if (netMessage.chattype() == ChatMessage::chatTypePrivate) {
698 unsigned playerId = netMessage.playerid();
699 PlayerInfo info;
700 if (client->GetCachedPlayerInfo(playerId, info))
701 client->GetCallback().SignalNetClientPrivateChatMsg(info.playerName, netMessage.chattext());
702 }
703 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_ChatRejectMessage) {
704 const ChatRejectMessage &netMessage = tmpPacket->GetMsg()->chatrejectmessage();
705 client->GetCallback().SignalNetClientGameChatMsg("(notice)", "Chat rejected: " + netMessage.chattext());
706 client->GetCallback().SignalNetClientLobbyChatMsg("(notice)", "Chat rejected: " + netMessage.chattext());
707 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_DialogMessage) {
708 // Message box - display it in the GUI.
709 const DialogMessage &netDialog = tmpPacket->GetMsg()->dialogmessage();
710 client->GetCallback().SignalNetClientMsgBox(netDialog.notificationtext());
711 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_PlayerListMessage) {
712 const PlayerListMessage &netPlayerList = tmpPacket->GetMsg()->playerlistmessage();
713
714 if (netPlayerList.playerlistnotification() == PlayerListMessage::playerListNew) {
715 client->GetCallback().SignalLobbyPlayerJoined(netPlayerList.playerid(), client->GetPlayerName(netPlayerList.playerid()));
716 } else if (netPlayerList.playerlistnotification() == PlayerListMessage::playerListLeft) {
717 client->GetCallback().SignalLobbyPlayerLeft(netPlayerList.playerid());
718 }
719 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameListNewMessage) {
720 // A new game was created on the server.
721 const GameListNewMessage &netListNew = tmpPacket->GetMsg()->gamelistnewmessage();
722
723 // Request player info for players if needed.
724 GameInfo tmpInfo;
725 list<unsigned> requestList;
726 // All players.
727 for (int i = 0; i < netListNew.playerids_size(); i++) {
728 PlayerInfo info;
729 unsigned playerId = netListNew.playerids(i);
730 if (!client->GetCachedPlayerInfo(playerId, info)) {
731 requestList.push_back(playerId);
732 }
733 tmpInfo.players.push_back(playerId);
734 }
735 // All spectators.
736 for (int i = 0; i < netListNew.spectatorids_size(); i++) {
737 PlayerInfo info;
738 unsigned playerId = netListNew.spectatorids(i);
739 if (!client->GetCachedPlayerInfo(playerId, info)) {
740 requestList.push_back(playerId);
741 }
742 tmpInfo.spectators.push_back(playerId);
743 }
744 // Send request for multiple players (will only act if list is non-empty).
745 client->RequestPlayerInfo(requestList);
746
747 tmpInfo.adminPlayerId = netListNew.adminplayerid();
748 tmpInfo.isPasswordProtected = netListNew.isprivate();
749 tmpInfo.mode = static_cast<GameMode>(netListNew.gamemode());
750 tmpInfo.name = netListNew.gameinfo().gamename();
751 NetPacket::GetGameData(netListNew.gameinfo(), tmpInfo.data);
752
753 client->AddGameInfo(netListNew.gameid(), tmpInfo);
754 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameListUpdateMessage) {
755 // An existing game was updated on the server.
756 const GameListUpdateMessage &netListUpdate = tmpPacket->GetMsg()->gamelistupdatemessage();
757 if (netListUpdate.gamemode() == netGameClosed)
758 client->RemoveGameInfo(netListUpdate.gameid());
759 else
760 client->UpdateGameInfoMode(netListUpdate.gameid(), static_cast<GameMode>(netListUpdate.gamemode()));
761 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameListPlayerJoinedMessage) {
762 const GameListPlayerJoinedMessage &netListJoined = tmpPacket->GetMsg()->gamelistplayerjoinedmessage();
763
764 client->ModifyGameInfoAddPlayer(netListJoined.gameid(), netListJoined.playerid());
765 // Request player info if needed.
766 PlayerInfo info;
767 if (!client->GetCachedPlayerInfo(netListJoined.playerid(), info)) {
768 client->RequestPlayerInfo(netListJoined.playerid());
769 }
770 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameListPlayerLeftMessage) {
771 const GameListPlayerLeftMessage &netListLeft = tmpPacket->GetMsg()->gamelistplayerleftmessage();
772
773 client->ModifyGameInfoRemovePlayer(netListLeft.gameid(), netListLeft.playerid());
774 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameListSpectatorJoinedMessage) {
775 const GameListSpectatorJoinedMessage &netListJoined = tmpPacket->GetMsg()->gamelistspectatorjoinedmessage();
776
777 client->ModifyGameInfoAddSpectator(netListJoined.gameid(), netListJoined.playerid());
778 // Request player info if needed.
779 PlayerInfo info;
780 if (!client->GetCachedPlayerInfo(netListJoined.playerid(), info)) {
781 client->RequestPlayerInfo(netListJoined.playerid());
782 }
783 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameListSpectatorLeftMessage) {
784 const GameListSpectatorLeftMessage &netListLeft = tmpPacket->GetMsg()->gamelistspectatorleftmessage();
785
786 client->ModifyGameInfoRemoveSpectator(netListLeft.gameid(), netListLeft.playerid());
787 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameListAdminChangedMessage) {
788 const GameListAdminChangedMessage &netListAdmin = tmpPacket->GetMsg()->gamelistadminchangedmessage();
789
790 client->UpdateGameInfoAdmin(netListAdmin.gameid(), netListAdmin.newadminplayerid());
791 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_StartKickPetitionMessage) {
792 const StartKickPetitionMessage &netStartPetition = tmpPacket->GetMsg()->startkickpetitionmessage();
793 client->StartPetition(netStartPetition.petitionid(), netStartPetition.proposingplayerid(),
794 netStartPetition.kickplayerid(), netStartPetition.kicktimeoutsec(), netStartPetition.numvotesneededtokick());
795 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_KickPetitionUpdateMessage) {
796 const KickPetitionUpdateMessage &netPetitionUpdate = tmpPacket->GetMsg()->kickpetitionupdatemessage();
797 client->UpdatePetition(netPetitionUpdate.petitionid(), netPetitionUpdate.numvotesagainstkicking(),
798 netPetitionUpdate.numvotesinfavourofkicking(), netPetitionUpdate.numvotesneededtokick());
799 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_EndKickPetitionMessage) {
800 const EndKickPetitionMessage &netEndPetition = tmpPacket->GetMsg()->endkickpetitionmessage();
801 client->EndPetition(netEndPetition.petitionid());
802 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AvatarHeaderMessage) {
803 const AvatarHeaderMessage &netAvatarHeader = tmpPacket->GetMsg()->avatarheadermessage();
804 client->AddTempAvatarFile(netAvatarHeader.requestid(), netAvatarHeader.avatarsize(), static_cast<AvatarFileType>(netAvatarHeader.avatartype()));
805 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AvatarDataMessage) {
806 const AvatarDataMessage &netAvatarData = tmpPacket->GetMsg()->avatardatamessage();
807 vector<unsigned char> fileData(netAvatarData.avatarblock().size());
808 memcpy(&fileData[0], netAvatarData.avatarblock().data(), netAvatarData.avatarblock().size());
809 client->StoreInTempAvatarFile(netAvatarData.requestid(), fileData);
810 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AvatarEndMessage) {
811 const AvatarEndMessage &netAvatarEnd = tmpPacket->GetMsg()->avatarendmessage();
812 client->CompleteTempAvatarFile(netAvatarEnd.requestid());
813 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_UnknownAvatarMessage) {
814 const UnknownAvatarMessage &netUnknownAvatar = tmpPacket->GetMsg()->unknownavatarmessage();
815 client->SetUnknownAvatar(netUnknownAvatar.requestid());
816 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_ReportAvatarAckMessage) {
817 const ReportAvatarAckMessage &netReportAck = tmpPacket->GetMsg()->reportavatarackmessage();
818 unsigned msgCode;
819 switch (netReportAck.reportavatarresult()) {
820 case ReportAvatarAckMessage::avatarReportAccepted:
821 msgCode = MSG_NET_AVATAR_REPORT_ACCEPTED;
822 break;
823 case ReportAvatarAckMessage::avatarReportDuplicate:
824 msgCode = MSG_NET_AVATAR_REPORT_DUP;
825 break;
826 default:
827 msgCode = MSG_NET_AVATAR_REPORT_REJECTED;
828 break;
829 }
830 client->GetCallback().SignalNetClientMsgBox(msgCode);
831 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_ReportGameAckMessage) {
832 const ReportGameAckMessage &netReportAck = tmpPacket->GetMsg()->reportgameackmessage();
833 unsigned msgCode;
834 switch (netReportAck.reportgameresult()) {
835 case ReportGameAckMessage::gameReportAccepted:
836 msgCode = MSG_NET_GAMENAME_REPORT_ACCEPTED;
837 break;
838 case ReportGameAckMessage::gameReportDuplicate:
839 msgCode = MSG_NET_GAMENAME_REPORT_DUP;
840 break;
841 default:
842 msgCode = MSG_NET_GAMENAME_REPORT_REJECTED;
843 break;
844 }
845 client->GetCallback().SignalNetClientMsgBox(msgCode);
846 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AdminRemoveGameAckMessage) {
847 const AdminRemoveGameAckMessage &netRemoveAck = tmpPacket->GetMsg()->adminremovegameackmessage();
848 unsigned msgCode;
849 switch (netRemoveAck.removegameresult()) {
850 case AdminRemoveGameAckMessage::gameRemoveAccepted:
851 msgCode = MSG_NET_ADMIN_REMOVE_GAME_ACCEPTED;
852 break;
853 default:
854 msgCode = MSG_NET_ADMIN_REMOVE_GAME_REJECTED;
855 break;
856 }
857 client->GetCallback().SignalNetClientMsgBox(msgCode);
858 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AdminBanPlayerAckMessage) {
859 const AdminBanPlayerAckMessage &netBanAck = tmpPacket->GetMsg()->adminbanplayerackmessage();
860 unsigned msgCode;
861 switch (netBanAck.banplayerresult()) {
862 case AdminBanPlayerAckMessage::banPlayerAccepted:
863 msgCode = MSG_NET_ADMIN_BAN_PLAYER_ACCEPTED;
864 break;
865 case AdminBanPlayerAckMessage::banPlayerPending:
866 msgCode = MSG_NET_ADMIN_BAN_PLAYER_PENDING;
867 break;
868 case AdminBanPlayerAckMessage::banPlayerNoDB:
869 msgCode = MSG_NET_ADMIN_BAN_PLAYER_NODB;
870 break;
871 case AdminBanPlayerAckMessage::banPlayerDBError:
872 msgCode = MSG_NET_ADMIN_BAN_PLAYER_DBERROR;
873 break;
874 default:
875 msgCode = MSG_NET_ADMIN_BAN_PLAYER_REJECTED;
876 break;
877 }
878 client->GetCallback().SignalNetClientMsgBox(msgCode);
879 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_StatisticsMessage) {
880 const StatisticsMessage &netStatistics = tmpPacket->GetMsg()->statisticsmessage();
881
882 unsigned numStats = netStatistics.statisticsdata_size();
883 // Request player info for players if needed.
884 if (numStats) {
885 ServerStats tmpStats;
886 for (unsigned i = 0; i < numStats; i++) {
887 if (netStatistics.statisticsdata(i).statisticstype() == StatisticsMessage::StatisticsData::statNumberOfPlayers)
888 tmpStats.numberOfPlayersOnServer = netStatistics.statisticsdata(i).statisticsvalue();
889 }
890 client->UpdateStatData(tmpStats);
891 }
892 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_ErrorMessage) {
893 // Server reported an error.
894 const ErrorMessage &netError = tmpPacket->GetMsg()->errormessage();
895 // Show the error.
896 throw ClientException(__FILE__, __LINE__, NetPacket::NetErrorToGameError(netError.errorreason()), 0);
897 }
898
899 InternalHandlePacket(client, tmpPacket);
900 }
901
902 //-----------------------------------------------------------------------------
903
904 ClientStateStartSession &
Instance()905 ClientStateStartSession::Instance()
906 {
907 static ClientStateStartSession state;
908 return state;
909 }
910
ClientStateStartSession()911 ClientStateStartSession::ClientStateStartSession()
912 {
913 }
914
~ClientStateStartSession()915 ClientStateStartSession::~ClientStateStartSession()
916 {
917 }
918
919 void
Enter(boost::shared_ptr<ClientThread> client)920 ClientStateStartSession::Enter(boost::shared_ptr<ClientThread> client)
921 {
922 // Now we finally start receiving data.
923 client->StartAsyncRead();
924 }
925
926 void
Exit(boost::shared_ptr<ClientThread>)927 ClientStateStartSession::Exit(boost::shared_ptr<ClientThread> /*client*/)
928 {
929 }
930
931 void
InternalHandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)932 ClientStateStartSession::InternalHandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
933 {
934 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AnnounceMessage) {
935 // Server has send announcement - check data.
936 const AnnounceMessage &netAnnounce = tmpPacket->GetMsg()->announcemessage();
937 // Check current game version.
938 if (netAnnounce.latestgameversion().majorversion() != POKERTH_VERSION_MAJOR
939 || netAnnounce.latestgameversion().minorversion() != POKERTH_VERSION_MINOR) {
940 client->GetCallback().SignalNetClientNotification(NTF_NET_NEW_RELEASE_AVAILABLE);
941 } else if (POKERTH_BETA_REVISION && netAnnounce.latestbetarevision() != POKERTH_BETA_REVISION) {
942 client->GetCallback().SignalNetClientNotification(NTF_NET_OUTDATED_BETA);
943 }
944 ClientContext &context = client->GetContext();
945
946 // CASE 1: Authenticated login (username, challenge/response for password).
947 if (netAnnounce.servertype() == AnnounceMessage::serverTypeInternetAuth) {
948 client->GetCallback().SignalNetClientLoginShow();
949 client->SetState(ClientStateWaitEnterLogin::Instance());
950 }
951 // CASE 2: Unauthenticated login (network game or dedicated server without auth backend).
952 else if (netAnnounce.servertype() == AnnounceMessage::serverTypeInternetNoAuth
953 || netAnnounce.servertype() == AnnounceMessage::serverTypeLAN) {
954 boost::shared_ptr<NetPacket> init(new NetPacket);
955 init->GetMsg()->set_messagetype(PokerTHMessage::Type_InitMessage);
956 InitMessage *netInit = init->GetMsg()->mutable_initmessage();
957 netInit->mutable_requestedversion()->set_majorversion(NET_VERSION_MAJOR);
958 netInit->mutable_requestedversion()->set_minorversion(NET_VERSION_MINOR);
959 netInit->set_buildid(0);
960 if (!context.GetSessionGuid().empty()) {
961 netInit->set_mylastsessionid(context.GetSessionGuid());
962 }
963 if (!context.GetServerPassword().empty()) {
964 netInit->set_authserverpassword(context.GetServerPassword());
965 }
966 netInit->set_login(InitMessage::unauthenticatedLogin);
967 netInit->set_nickname(context.GetPlayerName());
968 string avatarFile = client->GetQtToolsInterface().stringFromUtf8(context.GetAvatarFile());
969 if (!avatarFile.empty()) {
970 MD5Buf tmpMD5;
971 if (client->GetAvatarManager().GetHashForAvatar(avatarFile, tmpMD5)) {
972 // Send MD5 hash of avatar.
973 netInit->set_avatarhash(tmpMD5.GetData(), MD5_DATA_SIZE);
974 }
975 }
976 client->GetSender().Send(context.GetSessionData(), init);
977 client->SetState(ClientStateWaitSession::Instance());
978 }
979 }
980 }
981
982 //-----------------------------------------------------------------------------
983
984 ClientStateWaitEnterLogin &
Instance()985 ClientStateWaitEnterLogin::Instance()
986 {
987 static ClientStateWaitEnterLogin state;
988 return state;
989 }
990
ClientStateWaitEnterLogin()991 ClientStateWaitEnterLogin::ClientStateWaitEnterLogin()
992 {
993 }
994
~ClientStateWaitEnterLogin()995 ClientStateWaitEnterLogin::~ClientStateWaitEnterLogin()
996 {
997 }
998
999 void
Enter(boost::shared_ptr<ClientThread> client)1000 ClientStateWaitEnterLogin::Enter(boost::shared_ptr<ClientThread> client)
1001 {
1002 client->GetStateTimer().expires_from_now(
1003 milliseconds(CLIENT_WAIT_TIMEOUT_MSEC));
1004 client->GetStateTimer().async_wait(
1005 boost::bind(
1006 &ClientStateWaitEnterLogin::TimerLoop, this, boost::asio::placeholders::error, client));
1007 }
1008
1009 void
Exit(boost::shared_ptr<ClientThread> client)1010 ClientStateWaitEnterLogin::Exit(boost::shared_ptr<ClientThread> client)
1011 {
1012 client->GetStateTimer().cancel();
1013 }
1014
1015 void
HandlePacket(boost::shared_ptr<ClientThread>,boost::shared_ptr<NetPacket> tmpPacket)1016 ClientStateWaitEnterLogin::HandlePacket(boost::shared_ptr<ClientThread> /*client*/, boost::shared_ptr<NetPacket> tmpPacket)
1017 {
1018 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_ErrorMessage) {
1019 // Server reported an error.
1020 const ErrorMessage &netError = tmpPacket->GetMsg()->errormessage();
1021 // Show the error.
1022 throw ClientException(__FILE__, __LINE__, NetPacket::NetErrorToGameError(netError.errorreason()), 0);
1023 }
1024 }
1025
1026 void
TimerLoop(const boost::system::error_code & ec,boost::shared_ptr<ClientThread> client)1027 ClientStateWaitEnterLogin::TimerLoop(const boost::system::error_code& ec, boost::shared_ptr<ClientThread> client)
1028 {
1029 if (!ec && &client->GetState() == this) {
1030 ClientThread::LoginData loginData;
1031 if (client->GetLoginData(loginData)) {
1032 ClientContext &context = client->GetContext();
1033 boost::shared_ptr<NetPacket> init(new NetPacket);
1034 init->GetMsg()->set_messagetype(PokerTHMessage::Type_InitMessage);
1035 InitMessage *netInit = init->GetMsg()->mutable_initmessage();
1036 netInit->mutable_requestedversion()->set_majorversion(NET_VERSION_MAJOR);
1037 netInit->mutable_requestedversion()->set_minorversion(NET_VERSION_MINOR);
1038 netInit->set_buildid(0);
1039 if (!context.GetSessionGuid().empty()) {
1040 netInit->set_mylastsessionid(context.GetSessionGuid());
1041 }
1042 if (!context.GetServerPassword().empty()) {
1043 netInit->set_authserverpassword(context.GetServerPassword());
1044 }
1045
1046 context.SetPlayerName(loginData.userName);
1047
1048 // Handle guest login first.
1049 if (loginData.isGuest) {
1050 context.SetPassword("");
1051 context.SetPlayerRights(PLAYER_RIGHTS_GUEST);
1052 netInit->set_login(InitMessage::guestLogin);
1053 netInit->set_nickname(context.GetPlayerName());
1054
1055 client->GetSender().Send(context.GetSessionData(), init);
1056 client->SetState(ClientStateWaitSession::Instance());
1057 }
1058 // If the player is not a guest, authenticate.
1059 else {
1060 context.SetPassword(loginData.password);
1061 netInit->set_login(InitMessage::authenticatedLogin);
1062 // Send authentication user data for challenge/response in init.
1063 boost::shared_ptr<SessionData> tmpSession = context.GetSessionData();
1064 tmpSession->CreateClientAuthSession(client->GetAuthContext(), context.GetPlayerName(), context.GetPassword());
1065 if (!tmpSession->AuthStep(1, ""))
1066 throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PASSWORD, 0);
1067 string outUserData(tmpSession->AuthGetNextOutMsg());
1068 netInit->set_clientuserdata(outUserData);
1069 string avatarFile = client->GetQtToolsInterface().stringFromUtf8(context.GetAvatarFile());
1070 if (!avatarFile.empty()) {
1071 MD5Buf tmpMD5;
1072 if (client->GetAvatarManager().GetHashForAvatar(avatarFile, tmpMD5)) {
1073 // TODO: use sha1.
1074 netInit->set_avatarhash(tmpMD5.GetData(), MD5_DATA_SIZE);
1075 }
1076 }
1077 client->GetSender().Send(context.GetSessionData(), init);
1078 client->SetState(ClientStateWaitAuthChallenge::Instance());
1079 }
1080 } else {
1081 client->GetStateTimer().expires_from_now(
1082 milliseconds(CLIENT_WAIT_TIMEOUT_MSEC));
1083 client->GetStateTimer().async_wait(
1084 boost::bind(
1085 &ClientStateWaitEnterLogin::TimerLoop, this, boost::asio::placeholders::error, client));
1086 }
1087 }
1088 }
1089
1090 //-----------------------------------------------------------------------------
1091
1092 ClientStateWaitAuthChallenge &
Instance()1093 ClientStateWaitAuthChallenge::Instance()
1094 {
1095 static ClientStateWaitAuthChallenge state;
1096 return state;
1097 }
1098
ClientStateWaitAuthChallenge()1099 ClientStateWaitAuthChallenge::ClientStateWaitAuthChallenge()
1100 {
1101 }
1102
~ClientStateWaitAuthChallenge()1103 ClientStateWaitAuthChallenge::~ClientStateWaitAuthChallenge()
1104 {
1105 }
1106
1107 void
Enter(boost::shared_ptr<ClientThread>)1108 ClientStateWaitAuthChallenge::Enter(boost::shared_ptr<ClientThread> /*client*/)
1109 {
1110 }
1111
1112 void
Exit(boost::shared_ptr<ClientThread>)1113 ClientStateWaitAuthChallenge::Exit(boost::shared_ptr<ClientThread> /*client*/)
1114 {
1115 }
1116
1117 void
InternalHandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)1118 ClientStateWaitAuthChallenge::InternalHandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
1119 {
1120 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AuthServerChallengeMessage) {
1121 const AuthServerChallengeMessage &netAuth = tmpPacket->GetMsg()->authserverchallengemessage();
1122 string challengeStr(netAuth.serverchallenge());
1123 boost::shared_ptr<SessionData> tmpSession = client->GetContext().GetSessionData();
1124 if (!tmpSession->AuthStep(2, challengeStr.c_str()))
1125 throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PASSWORD, 0);
1126 string outUserData(tmpSession->AuthGetNextOutMsg());
1127
1128 boost::shared_ptr<NetPacket> packet(new NetPacket);
1129 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_AuthClientResponseMessage);
1130 AuthClientResponseMessage *outAuth = packet->GetMsg()->mutable_authclientresponsemessage();
1131 outAuth->set_clientresponse(outUserData);
1132 client->GetSender().Send(tmpSession, packet);
1133 client->SetState(ClientStateWaitAuthVerify::Instance());
1134 }
1135 }
1136
1137 //-----------------------------------------------------------------------------
1138
1139 ClientStateWaitAuthVerify &
Instance()1140 ClientStateWaitAuthVerify::Instance()
1141 {
1142 static ClientStateWaitAuthVerify state;
1143 return state;
1144 }
1145
ClientStateWaitAuthVerify()1146 ClientStateWaitAuthVerify::ClientStateWaitAuthVerify()
1147 {
1148 }
1149
~ClientStateWaitAuthVerify()1150 ClientStateWaitAuthVerify::~ClientStateWaitAuthVerify()
1151 {
1152 }
1153
1154 void
Enter(boost::shared_ptr<ClientThread>)1155 ClientStateWaitAuthVerify::Enter(boost::shared_ptr<ClientThread> /*client*/)
1156 {
1157 }
1158
1159 void
Exit(boost::shared_ptr<ClientThread>)1160 ClientStateWaitAuthVerify::Exit(boost::shared_ptr<ClientThread> /*client*/)
1161 {
1162 }
1163
1164 void
InternalHandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)1165 ClientStateWaitAuthVerify::InternalHandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
1166 {
1167 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AuthServerVerificationMessage) {
1168 // Check subtype.
1169 const AuthServerVerificationMessage &netAuth = tmpPacket->GetMsg()->authserververificationmessage();
1170 string verificationStr(netAuth.serververification());
1171 boost::shared_ptr<SessionData> tmpSession = client->GetContext().GetSessionData();
1172 if (!tmpSession->AuthStep(3, verificationStr.c_str()))
1173 throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PASSWORD, 0);
1174
1175 client->SetState(ClientStateWaitSession::Instance());
1176 }
1177 }
1178
1179 //-----------------------------------------------------------------------------
1180
1181 ClientStateWaitSession &
Instance()1182 ClientStateWaitSession::Instance()
1183 {
1184 static ClientStateWaitSession state;
1185 return state;
1186 }
1187
ClientStateWaitSession()1188 ClientStateWaitSession::ClientStateWaitSession()
1189 {
1190 }
1191
~ClientStateWaitSession()1192 ClientStateWaitSession::~ClientStateWaitSession()
1193 {
1194 }
1195
1196 void
Enter(boost::shared_ptr<ClientThread>)1197 ClientStateWaitSession::Enter(boost::shared_ptr<ClientThread> /*client*/)
1198 {
1199 }
1200
1201 void
Exit(boost::shared_ptr<ClientThread>)1202 ClientStateWaitSession::Exit(boost::shared_ptr<ClientThread> /*client*/)
1203 {
1204 }
1205
1206 void
InternalHandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)1207 ClientStateWaitSession::InternalHandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
1208 {
1209 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_InitAckMessage) {
1210 // Everything is fine - we are in the lobby.
1211 const InitAckMessage &netInitAck = tmpPacket->GetMsg()->initackmessage();
1212 client->SetGuiPlayerId(netInitAck.yourplayerid());
1213
1214 client->GetContext().SetSessionGuid(netInitAck.yoursessionid());
1215 client->SetSessionEstablished(true);
1216 client->GetCallback().SignalNetClientConnect(MSG_SOCK_SESSION_DONE);
1217 if (netInitAck.has_rejoingameid())
1218 client->GetCallback().SignalNetClientRejoinPossible(netInitAck.rejoingameid());
1219 client->SetState(ClientStateWaitJoin::Instance());
1220 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AvatarRequestMessage) {
1221 // Before letting us join the lobby, the server requests our avatar.
1222 const AvatarRequestMessage &netAvatarRequest = tmpPacket->GetMsg()->avatarrequestmessage();
1223
1224 // TODO compare SHA1.
1225 NetPacketList tmpList;
1226 int avatarError = client->GetAvatarManager().AvatarFileToNetPackets(
1227 client->GetQtToolsInterface().stringFromUtf8(client->GetContext().GetAvatarFile()),
1228 netAvatarRequest.requestid(),
1229 tmpList);
1230
1231 if (!avatarError)
1232 client->GetSender().Send(client->GetContext().GetSessionData(), tmpList);
1233 else
1234 throw ClientException(__FILE__, __LINE__, avatarError, 0);
1235 }
1236 }
1237
1238 //-----------------------------------------------------------------------------
1239
1240 ClientStateWaitJoin &
Instance()1241 ClientStateWaitJoin::Instance()
1242 {
1243 static ClientStateWaitJoin state;
1244 return state;
1245 }
1246
ClientStateWaitJoin()1247 ClientStateWaitJoin::ClientStateWaitJoin()
1248 {
1249 }
1250
~ClientStateWaitJoin()1251 ClientStateWaitJoin::~ClientStateWaitJoin()
1252 {
1253 }
1254
1255 void
Enter(boost::shared_ptr<ClientThread>)1256 ClientStateWaitJoin::Enter(boost::shared_ptr<ClientThread> /*client*/)
1257 {
1258 }
1259
1260 void
Exit(boost::shared_ptr<ClientThread>)1261 ClientStateWaitJoin::Exit(boost::shared_ptr<ClientThread> /*client*/)
1262 {
1263 }
1264
1265 void
InternalHandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)1266 ClientStateWaitJoin::InternalHandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
1267 {
1268 ClientContext &context = client->GetContext();
1269
1270 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_JoinGameAckMessage) {
1271 const JoinGameAckMessage &netJoinAck = tmpPacket->GetMsg()->joingameackmessage();
1272 // Successfully joined a game.
1273 client->SetGameId(netJoinAck.gameid());
1274 GameData tmpData;
1275 NetPacket::GetGameData(netJoinAck.gameinfo(), tmpData);
1276 client->SetGameData(tmpData);
1277 client->ModifyGameInfoClearSpectatorsDuringGame();
1278
1279 // Player number is 0 on init. Will be set when the game starts.
1280 boost::shared_ptr<PlayerData> playerData(
1281 new PlayerData(client->GetGuiPlayerId(), 0, PLAYER_TYPE_HUMAN,
1282 context.GetPlayerRights(), netJoinAck.areyougameadmin()));
1283 playerData->SetName(context.GetPlayerName());
1284 playerData->SetAvatarFile(context.GetAvatarFile());
1285 client->AddPlayerData(playerData);
1286
1287 client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_JOIN);
1288 client->SetState(ClientStateWaitGame::Instance());
1289 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_JoinGameFailedMessage) {
1290 // Failed to join a game.
1291 const JoinGameFailedMessage &netJoinFailed = tmpPacket->GetMsg()->joingamefailedmessage();
1292
1293 int failureCode;
1294 switch (netJoinFailed.joingamefailurereason()) {
1295 case JoinGameFailedMessage::invalidGame :
1296 failureCode = NTF_NET_JOIN_GAME_INVALID;
1297 break;
1298 case JoinGameFailedMessage::gameIsFull :
1299 failureCode = NTF_NET_JOIN_GAME_FULL;
1300 break;
1301 case JoinGameFailedMessage::gameIsRunning :
1302 failureCode = NTF_NET_JOIN_ALREADY_RUNNING;
1303 break;
1304 case JoinGameFailedMessage::invalidPassword :
1305 failureCode = NTF_NET_JOIN_INVALID_PASSWORD;
1306 break;
1307 case JoinGameFailedMessage::notAllowedAsGuest :
1308 failureCode = NTF_NET_JOIN_GUEST_FORBIDDEN;
1309 break;
1310 case JoinGameFailedMessage::notInvited :
1311 failureCode = NTF_NET_JOIN_NOT_INVITED;
1312 break;
1313 case JoinGameFailedMessage::gameNameInUse :
1314 failureCode = NTF_NET_JOIN_GAME_NAME_IN_USE;
1315 break;
1316 case JoinGameFailedMessage::badGameName :
1317 failureCode = NTF_NET_JOIN_GAME_BAD_NAME;
1318 break;
1319 case JoinGameFailedMessage::invalidSettings :
1320 failureCode = NTF_NET_JOIN_INVALID_SETTINGS;
1321 break;
1322 case JoinGameFailedMessage::ipAddressBlocked :
1323 failureCode = NTF_NET_JOIN_IP_BLOCKED;
1324 break;
1325 case JoinGameFailedMessage::rejoinFailed :
1326 failureCode = NTF_NET_JOIN_REJOIN_FAILED;
1327 break;
1328 default :
1329 failureCode = NTF_NET_INTERNAL;
1330 break;
1331 }
1332
1333 client->GetCallback().SignalNetClientNotification(failureCode);
1334 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_InviteNotifyMessage) {
1335 const InviteNotifyMessage &netInvNotify = tmpPacket->GetMsg()->invitenotifymessage();
1336 if (netInvNotify.playeridwho() == client->GetGuiPlayerId()) {
1337 client->GetCallback().SignalSelfGameInvitation(netInvNotify.gameid(), netInvNotify.playeridbywhom());
1338 }
1339 }
1340 }
1341
1342 //-----------------------------------------------------------------------------
1343
1344 ClientStateWaitGame &
Instance()1345 ClientStateWaitGame::Instance()
1346 {
1347 static ClientStateWaitGame state;
1348 return state;
1349 }
1350
ClientStateWaitGame()1351 ClientStateWaitGame::ClientStateWaitGame()
1352 {
1353 }
1354
~ClientStateWaitGame()1355 ClientStateWaitGame::~ClientStateWaitGame()
1356 {
1357 }
1358
1359 void
Enter(boost::shared_ptr<ClientThread>)1360 ClientStateWaitGame::Enter(boost::shared_ptr<ClientThread> /*client*/)
1361 {
1362 }
1363
1364 void
Exit(boost::shared_ptr<ClientThread>)1365 ClientStateWaitGame::Exit(boost::shared_ptr<ClientThread> /*client*/)
1366 {
1367 }
1368
1369 void
InternalHandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)1370 ClientStateWaitGame::InternalHandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
1371 {
1372 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_StartEventMessage) {
1373 const StartEventMessage &netStartEvent = tmpPacket->GetMsg()->starteventmessage();
1374 if (netStartEvent.starteventtype() == StartEventMessage::rejoinEvent) {
1375 client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_SYNCREJOIN);
1376 } else {
1377 client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_SYNCSTART);
1378 }
1379 client->SetState(ClientStateSynchronizeStart::Instance());
1380 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_InviteNotifyMessage) {
1381 const InviteNotifyMessage &netInvNotify = tmpPacket->GetMsg()->invitenotifymessage();
1382 client->GetCallback().SignalPlayerGameInvitation(
1383 netInvNotify.gameid(),
1384 netInvNotify.playeridwho(),
1385 netInvNotify.playeridbywhom());
1386 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_RejectInvNotifyMessage) {
1387 const RejectInvNotifyMessage &netRejNotify = tmpPacket->GetMsg()->rejectinvnotifymessage();
1388 client->GetCallback().SignalRejectedGameInvitation(
1389 netRejNotify.gameid(),
1390 netRejNotify.playerid(),
1391 static_cast<DenyGameInvitationReason>(netRejNotify.playerrejectreason()));
1392 }
1393 }
1394
1395 //-----------------------------------------------------------------------------
1396
1397 ClientStateSynchronizeStart &
Instance()1398 ClientStateSynchronizeStart::Instance()
1399 {
1400 static ClientStateSynchronizeStart state;
1401 return state;
1402 }
1403
ClientStateSynchronizeStart()1404 ClientStateSynchronizeStart::ClientStateSynchronizeStart()
1405 {
1406 }
1407
~ClientStateSynchronizeStart()1408 ClientStateSynchronizeStart::~ClientStateSynchronizeStart()
1409 {
1410 }
1411
1412 void
Enter(boost::shared_ptr<ClientThread> client)1413 ClientStateSynchronizeStart::Enter(boost::shared_ptr<ClientThread> client)
1414 {
1415 client->GetStateTimer().expires_from_now(
1416 milliseconds(CLIENT_WAIT_TIMEOUT_MSEC));
1417 client->GetStateTimer().async_wait(
1418 boost::bind(
1419 &ClientStateSynchronizeStart::TimerLoop, this, boost::asio::placeholders::error, client));
1420 }
1421
1422 void
Exit(boost::shared_ptr<ClientThread> client)1423 ClientStateSynchronizeStart::Exit(boost::shared_ptr<ClientThread> client)
1424 {
1425 client->GetStateTimer().cancel();
1426 }
1427
1428 void
TimerLoop(const boost::system::error_code & ec,boost::shared_ptr<ClientThread> client)1429 ClientStateSynchronizeStart::TimerLoop(const boost::system::error_code& ec, boost::shared_ptr<ClientThread> client)
1430 {
1431 if (!ec && &client->GetState() == this) {
1432 if (client->IsSynchronized()) {
1433 // Acknowledge start.
1434 boost::shared_ptr<NetPacket> startAck(new NetPacket);
1435 startAck->GetMsg()->set_messagetype(PokerTHMessage::Type_StartEventAckMessage);
1436 StartEventAckMessage *netStartAck = startAck->GetMsg()->mutable_starteventackmessage();
1437 netStartAck->set_gameid(client->GetGameId());
1438
1439 client->GetSender().Send(client->GetContext().GetSessionData(), startAck);
1440 // Unsubscribe lobby messages.
1441 client->UnsubscribeLobbyMsg();
1442
1443 client->SetState(ClientStateWaitStart::Instance());
1444 } else {
1445 client->GetStateTimer().expires_from_now(
1446 milliseconds(CLIENT_WAIT_TIMEOUT_MSEC));
1447 client->GetStateTimer().async_wait(
1448 boost::bind(
1449 &ClientStateSynchronizeStart::TimerLoop, this, boost::asio::placeholders::error, client));
1450 }
1451 }
1452 }
1453
1454 void
InternalHandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)1455 ClientStateSynchronizeStart::InternalHandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
1456 {
1457 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameStartInitialMessage) {
1458 // Try to start anyway. Terminating here is very bad because rejoin is not possible then.
1459 // Unsubscribe lobby messages.
1460 client->UnsubscribeLobbyMsg();
1461 client->SetState(ClientStateWaitStart::Instance());
1462 // Forward the game start message to the next state.
1463 client->GetState().HandlePacket(client, tmpPacket);
1464 }
1465 }
1466
1467 //-----------------------------------------------------------------------------
1468
1469 ClientStateWaitStart &
Instance()1470 ClientStateWaitStart::Instance()
1471 {
1472 static ClientStateWaitStart state;
1473 return state;
1474 }
1475
ClientStateWaitStart()1476 ClientStateWaitStart::ClientStateWaitStart()
1477 {
1478 }
1479
~ClientStateWaitStart()1480 ClientStateWaitStart::~ClientStateWaitStart()
1481 {
1482 }
1483
1484 void
Enter(boost::shared_ptr<ClientThread>)1485 ClientStateWaitStart::Enter(boost::shared_ptr<ClientThread> /*client*/)
1486 {
1487 }
1488
1489 void
Exit(boost::shared_ptr<ClientThread>)1490 ClientStateWaitStart::Exit(boost::shared_ptr<ClientThread> /*client*/)
1491 {
1492 }
1493
1494 void
InternalHandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)1495 ClientStateWaitStart::InternalHandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
1496 {
1497 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameStartInitialMessage
1498 || tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameStartRejoinMessage) {
1499 PlayerIdList tmpPlayerList;
1500 unsigned tmpHandId = 0;
1501
1502 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameStartInitialMessage) {
1503 // Start the network game as client.
1504 const GameStartInitialMessage &netStartModeInitial = tmpPacket->GetMsg()->gamestartinitialmessage();
1505
1506 StartData startData;
1507 startData.startDealerPlayerId = netStartModeInitial.startdealerplayerid();
1508 startData.numberOfPlayers = netStartModeInitial.playerseats_size();
1509 client->SetStartData(startData);
1510
1511 // Set player numbers using the game start data slots.
1512 unsigned numPlayers = netStartModeInitial.playerseats_size();
1513 // Request player info for players if needed.
1514 if (numPlayers) {
1515 for (unsigned i = 0; i < numPlayers; i++) {
1516 unsigned playerId = netStartModeInitial.playerseats(i);
1517 boost::shared_ptr<PlayerData> tmpPlayer = client->GetPlayerDataByUniqueId(playerId);
1518 if (!tmpPlayer)
1519 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1520 tmpPlayer->SetNumber(i);
1521 }
1522 } else {
1523 throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PLAYER_COUNT, 0);
1524 }
1525 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_GameStartRejoinMessage) {
1526 const GameStartRejoinMessage &netStartModeRejoin = tmpPacket->GetMsg()->gamestartrejoinmessage();
1527
1528 StartData startData;
1529 startData.startDealerPlayerId = netStartModeRejoin.startdealerplayerid();
1530 startData.numberOfPlayers = netStartModeRejoin.rejoinplayerdata_size();
1531 client->SetStartData(startData);
1532 tmpHandId = netStartModeRejoin.handnum();
1533
1534 // Set player numbers using the game start data slots.
1535 unsigned numPlayers = netStartModeRejoin.rejoinplayerdata_size();
1536 // Request player info for players if needed.
1537 if (numPlayers) {
1538 for (unsigned i = 0; i < numPlayers; i++) {
1539 const GameStartRejoinMessage::RejoinPlayerData &playerData = netStartModeRejoin.rejoinplayerdata(i);
1540 boost::shared_ptr<PlayerData> tmpPlayer = client->GetPlayerDataByUniqueId(playerData.playerid());
1541 if (!tmpPlayer) {
1542 // If the player is not found: The corresponding session left. We need to create a generic player object.
1543 // In order to have a complete seat list, we need all players, even those who left.
1544 tmpPlayer = client->CreatePlayerData(playerData.playerid(), false);
1545 client->AddPlayerData(tmpPlayer);
1546 tmpPlayerList.push_back(playerData.playerid());
1547 }
1548 tmpPlayer->SetNumber(i);
1549 tmpPlayer->SetStartCash(playerData.playermoney());
1550 }
1551 } else
1552 throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PLAYER_COUNT, 0);
1553 }
1554 client->InitGame();
1555 client->GetGame()->setCurrentHandID(tmpHandId);
1556 // We need to remove the temporary player data objects after creating the game.
1557 BOOST_FOREACH(unsigned tmpPlayerId, tmpPlayerList) {
1558 client->RemovePlayerData(tmpPlayerId, NTF_NET_REMOVED_ON_REQUEST);
1559 }
1560 client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_START);
1561 client->SetState(ClientStateWaitHand::Instance());
1562 }
1563 }
1564
1565 //-----------------------------------------------------------------------------
1566
1567 ClientStateWaitHand &
Instance()1568 ClientStateWaitHand::Instance()
1569 {
1570 static ClientStateWaitHand state;
1571 return state;
1572 }
1573
ClientStateWaitHand()1574 ClientStateWaitHand::ClientStateWaitHand()
1575 {
1576 }
1577
~ClientStateWaitHand()1578 ClientStateWaitHand::~ClientStateWaitHand()
1579 {
1580 }
1581
1582 void
Enter(boost::shared_ptr<ClientThread>)1583 ClientStateWaitHand::Enter(boost::shared_ptr<ClientThread> /*client*/)
1584 {
1585 }
1586
1587 void
Exit(boost::shared_ptr<ClientThread>)1588 ClientStateWaitHand::Exit(boost::shared_ptr<ClientThread> /*client*/)
1589 {
1590 }
1591
1592 void
InternalHandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)1593 ClientStateWaitHand::InternalHandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
1594 {
1595 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_HandStartMessage) {
1596 // Hand was started.
1597 // These are the cards. Good luck.
1598 const HandStartMessage &netHandStart = tmpPacket->GetMsg()->handstartmessage();
1599 int myCards[2];
1600 string userPassword(client->GetContext().GetPassword());
1601 if (netHandStart.has_plaincards() && userPassword.empty()) {
1602 const HandStartMessage::PlainCards &plainCards = netHandStart.plaincards();
1603 myCards[0] = (int)plainCards.plaincard1();
1604 myCards[1] = (int)plainCards.plaincard2();
1605 } else if (netHandStart.has_encryptedcards() && !userPassword.empty()) {
1606 const string &encryptedCards = netHandStart.encryptedcards();
1607 string plainCards;
1608 if (!CryptHelper::AES128Decrypt((const unsigned char *)userPassword.c_str(),
1609 (unsigned)userPassword.size(),
1610 (const unsigned char *)encryptedCards.data(),
1611 (unsigned)encryptedCards.size(),
1612 plainCards)) {
1613 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1614 }
1615 istringstream cardDataStream(plainCards);
1616 unsigned tmpPlayerId, tmpGameId;
1617 int tmpHandNum;
1618 cardDataStream >> tmpPlayerId;
1619 cardDataStream >> tmpGameId;
1620 cardDataStream >> tmpHandNum;
1621 if (tmpPlayerId != client->GetGuiPlayerId()
1622 || tmpGameId != client->GetGameId()
1623 || tmpHandNum != client->GetGame()->getCurrentHandID() + 1) {
1624 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1625 }
1626 cardDataStream >> myCards[0];
1627 cardDataStream >> myCards[1];
1628 }
1629 // Retrieve state for each seat (not based on player id).
1630 unsigned numPlayers = netHandStart.seatstates_size();
1631 // Request player info for players if needed.
1632 for (int i = 0; i < (int)numPlayers; i++) {
1633 NetPlayerState seatState = netHandStart.seatstates(i);
1634 int numberDiff = client->GetStartData().numberOfPlayers - client->GetOrigGuiPlayerNum();
1635 boost::shared_ptr<PlayerInterface> tmpPlayer = client->GetGame()->getPlayerByNumber((i + numberDiff) % client->GetStartData().numberOfPlayers);
1636 if (!tmpPlayer)
1637 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1638 switch (seatState) {
1639 case netPlayerStateNormal :
1640 tmpPlayer->setIsSessionActive(true);
1641 break;
1642 case netPlayerStateSessionInactive :
1643 tmpPlayer->setIsSessionActive(false);
1644 break;
1645 case netPlayerStateNoMoney :
1646 tmpPlayer->setMyCash(0);
1647 break;
1648 }
1649 }
1650
1651 // Basic synchronisation before a new hand is started.
1652 client->GetGui().waitForGuiUpdateDone();
1653 // Start new hand.
1654 client->GetGame()->getSeatsList()->front()->setMyCards(myCards);
1655 client->GetGame()->initHand();
1656 client->GetGame()->getCurrentHand()->setSmallBlind(netHandStart.smallblind());
1657 client->GetGame()->getCurrentHand()->getCurrentBeRo()->setMinimumRaise(2 * netHandStart.smallblind());
1658 client->GetGame()->startHand();
1659 client->GetGui().dealHoleCards();
1660 client->GetGui().refreshGameLabels(GAME_STATE_PREFLOP);
1661 client->GetGui().refreshPot();
1662 client->GetGui().waitForGuiUpdateDone();
1663
1664 client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_HAND_START);
1665 client->SetState(ClientStateRunHand::Instance());
1666 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_EndOfGameMessage) {
1667 boost::shared_ptr<Game> curGame = client->GetGame();
1668 if (curGame) {
1669 const EndOfGameMessage &netEndOfGame = tmpPacket->GetMsg()->endofgamemessage();
1670
1671 boost::shared_ptr<PlayerInterface> tmpPlayer = curGame->getPlayerByUniqueId(netEndOfGame.winnerplayerid());
1672 if (!tmpPlayer)
1673 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1674 client->GetGui().logPlayerWinGame(tmpPlayer->getMyName(), curGame->getMyGameID());
1675 // Resubscribe Lobby messages.
1676 client->ResubscribeLobbyMsg();
1677 // Show Lobby dialog.
1678 client->GetCallback().SignalNetClientWaitDialog();
1679 client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_END);
1680 client->SetState(ClientStateWaitGame::Instance());
1681 }
1682 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AfterHandShowCardsMessage) {
1683 const AfterHandShowCardsMessage &showCards = tmpPacket->GetMsg()->afterhandshowcardsmessage();
1684 const PlayerResult &r = showCards.playerresult();
1685
1686 boost::shared_ptr<PlayerInterface> tmpPlayer = client->GetGame()->getPlayerByUniqueId(r.playerid());
1687 if (!tmpPlayer)
1688 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1689
1690 int tmpCards[2];
1691 int bestHandPos[5];
1692 tmpCards[0] = static_cast<int>(r.resultcard1());
1693 tmpCards[1] = static_cast<int>(r.resultcard2());
1694 tmpPlayer->setMyCards(tmpCards);
1695 for (int num = 0; num < 5; num++) {
1696 bestHandPos[num] = r.besthandposition(num);
1697 }
1698 if (r.cardsvalue()) {
1699 tmpPlayer->setMyCardsValueInt(r.cardsvalue());
1700 }
1701 tmpPlayer->setMyBestHandPosition(bestHandPos);
1702 tmpPlayer->setMyCash(r.playermoney());
1703 tmpPlayer->setLastMoneyWon(r.moneywon());
1704
1705 client->GetCallback().SignalNetClientPostRiverShowCards(r.playerid());
1706 client->GetClientLog()->logHoleCardsHandName(client->GetGame()->getActivePlayerList(), tmpPlayer, true);
1707 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_PlayerIdChangedMessage) {
1708 boost::shared_ptr<Game> curGame = client->GetGame();
1709 if (curGame) {
1710 // Perform Id change.
1711 const PlayerIdChangedMessage &idChanged = tmpPacket->GetMsg()->playeridchangedmessage();
1712 boost::shared_ptr<PlayerInterface> tmpPlayer = curGame->getPlayerByUniqueId(idChanged.oldplayerid());
1713 if (!tmpPlayer)
1714 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1715 tmpPlayer->setMyUniqueID(idChanged.newplayerid());
1716 // This player is now active again.
1717 tmpPlayer->setMyStayOnTableStatus(true);
1718 // Also update the dealer, if necessary.
1719 curGame->replaceDealer(idChanged.oldplayerid(), idChanged.newplayerid());
1720 // Update the player name, if necessary.
1721 PlayerInfo info;
1722 if (client->GetCachedPlayerInfo(idChanged.newplayerid(), info)) {
1723 tmpPlayer->setMyName(info.playerName);
1724 }
1725 }
1726 }
1727 }
1728
1729 //-----------------------------------------------------------------------------
1730
1731 ClientStateRunHand &
Instance()1732 ClientStateRunHand::Instance()
1733 {
1734 static ClientStateRunHand state;
1735 return state;
1736 }
1737
ClientStateRunHand()1738 ClientStateRunHand::ClientStateRunHand()
1739 {
1740 }
1741
~ClientStateRunHand()1742 ClientStateRunHand::~ClientStateRunHand()
1743 {
1744 }
1745
1746 void
Enter(boost::shared_ptr<ClientThread>)1747 ClientStateRunHand::Enter(boost::shared_ptr<ClientThread> /*client*/)
1748 {
1749 }
1750
1751 void
Exit(boost::shared_ptr<ClientThread>)1752 ClientStateRunHand::Exit(boost::shared_ptr<ClientThread> /*client*/)
1753 {
1754 }
1755
1756 void
InternalHandlePacket(boost::shared_ptr<ClientThread> client,boost::shared_ptr<NetPacket> tmpPacket)1757 ClientStateRunHand::InternalHandlePacket(boost::shared_ptr<ClientThread> client, boost::shared_ptr<NetPacket> tmpPacket)
1758 {
1759 boost::shared_ptr<Game> curGame = client->GetGame();
1760 if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_PlayersActionDoneMessage) {
1761 const PlayersActionDoneMessage &netActionDone = tmpPacket->GetMsg()->playersactiondonemessage();
1762
1763 boost::shared_ptr<PlayerInterface> tmpPlayer = curGame->getPlayerByUniqueId(netActionDone.playerid());
1764 if (!tmpPlayer)
1765 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1766
1767 bool isBigBlind = false;
1768
1769 if (netActionDone.gamestate() == netStatePreflopSmallBlind) {
1770 curGame->getCurrentHand()->getCurrentBeRo()->setSmallBlindPositionId(tmpPlayer->getMyUniqueID());
1771 tmpPlayer->setMyButton(BUTTON_SMALL_BLIND);
1772 } else if (netActionDone.gamestate() == netStatePreflopBigBlind) {
1773 curGame->getCurrentHand()->getCurrentBeRo()->setBigBlindPositionId(tmpPlayer->getMyUniqueID());
1774 tmpPlayer->setMyButton(BUTTON_BIG_BLIND);
1775 isBigBlind = true;
1776 } else { // no blind -> log
1777 if (netActionDone.playeraction()) {
1778 assert((int)netActionDone.totalplayerbet() >= tmpPlayer->getMySet());
1779 client->GetGui().logPlayerActionMsg(
1780 tmpPlayer->getMyName(),
1781 netActionDone.playeraction(),
1782 netActionDone.totalplayerbet() - tmpPlayer->getMySet());
1783 client->GetClientLog()->logPlayerAction(
1784 tmpPlayer->getMyName(),
1785 client->GetClientLog()->transformPlayerActionLog(PlayerAction(netActionDone.playeraction())),
1786 netActionDone.totalplayerbet() - tmpPlayer->getMySet()
1787 );
1788 if (tmpPlayer->getMyID() == 0) {
1789 client->EndPing();
1790 }
1791 }
1792 // Update last players turn only after the blinds.
1793 curGame->getCurrentHand()->setPreviousPlayerID(tmpPlayer->getMyID());
1794 }
1795
1796 tmpPlayer->setMyAction(PlayerAction(netActionDone.playeraction()));
1797 tmpPlayer->setMySetAbsolute(netActionDone.totalplayerbet());
1798 tmpPlayer->setMyCash(netActionDone.playermoney());
1799 curGame->getCurrentHand()->getCurrentBeRo()->setHighestSet(netActionDone.highestset());
1800 curGame->getCurrentHand()->getCurrentBeRo()->setMinimumRaise(netActionDone.minimumraise());
1801 curGame->getCurrentHand()->getBoard()->collectSets();
1802 curGame->getCurrentHand()->switchRounds();
1803
1804 //log blinds sets after setting bigblind-button
1805 if (isBigBlind) {
1806 client->GetGui().logNewBlindsSetsMsg(
1807 curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getSmallBlindPositionId())->getMySet(),
1808 curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getBigBlindPositionId())->getMySet(),
1809 curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getSmallBlindPositionId())->getMyName(),
1810 curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getBigBlindPositionId())->getMyName());
1811 client->GetGui().flushLogAtHand();
1812 client->GetClientLog()->logNewHandMsg(
1813 curGame->getCurrentHandID(),
1814 curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getDealerPosition())->getMyID()+1,
1815 curGame->getCurrentHand()->getSmallBlind(),
1816 curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getSmallBlindPositionId())->getMyID()+1,
1817 curGame->getCurrentHand()->getSmallBlind()*2,
1818 curGame->getPlayerByUniqueId(curGame->getCurrentHand()->getCurrentBeRo()->getBigBlindPositionId())->getMyID()+1,
1819 curGame->getSeatsList()
1820 );
1821 }
1822
1823 // Stop the timeout for the player.
1824 client->GetGui().stopTimeoutAnimation(tmpPlayer->getMyID());
1825
1826 // Unmark last player in GUI.
1827 client->GetGui().refreshGroupbox(tmpPlayer->getMyID(), 3);
1828
1829 // Refresh GUI
1830 if (tmpPlayer->getMyID() == 0)
1831 client->GetGui().disableMyButtons();
1832 client->GetGui().refreshAction(tmpPlayer->getMyID(), tmpPlayer->getMyAction());
1833 client->GetGui().refreshPot();
1834 client->GetGui().refreshSet();
1835 client->GetGui().refreshCash();
1836 client->GetGui().refreshButton();
1837 client->GetGui().updateMyButtonsState();
1838 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_PlayersTurnMessage) {
1839 const PlayersTurnMessage &netPlayersTurn = tmpPacket->GetMsg()->playersturnmessage();
1840
1841 boost::shared_ptr<PlayerInterface> tmpPlayer = curGame->getPlayerByUniqueId(netPlayersTurn.playerid());
1842 if (!tmpPlayer)
1843 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1844
1845 // Set round.
1846 if (curGame->getCurrentHand()->getCurrentRound() != static_cast<GameState>(netPlayersTurn.gamestate())) {
1847 ResetPlayerActions(*curGame);
1848 curGame->getCurrentHand()->setCurrentRound(static_cast<GameState>(netPlayersTurn.gamestate()));
1849 client->GetClientLog()->setCurrentRound(static_cast<GameState>(netPlayersTurn.gamestate()));
1850 // Refresh actions.
1851 client->GetGui().refreshSet();
1852 client->GetGui().refreshAction();
1853 }
1854
1855 // Next player's turn.
1856 curGame->getCurrentHand()->getCurrentBeRo()->setCurrentPlayersTurnId(tmpPlayer->getMyID());
1857
1858 // Mark current player in GUI.
1859 int guiStatus = 2;
1860 if (!tmpPlayer->getMyActiveStatus())
1861 guiStatus = 0;
1862 else if (tmpPlayer->getMyAction() == PLAYER_ACTION_FOLD)
1863 guiStatus = 1;
1864 client->GetGui().refreshGroupbox(tmpPlayer->getMyID(), guiStatus);
1865 client->GetGui().refreshAction(tmpPlayer->getMyID(), PLAYER_ACTION_NONE);
1866
1867 // Start displaying the timeout for the player.
1868 client->GetGui().startTimeoutAnimation(tmpPlayer->getMyID(), client->GetGameData().playerActionTimeoutSec);
1869
1870 if (tmpPlayer->getMyID() == 0) // Is this the GUI player?
1871 client->GetGui().meInAction();
1872 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_DealFlopCardsMessage) {
1873 const DealFlopCardsMessage &netDealFlop = tmpPacket->GetMsg()->dealflopcardsmessage();
1874
1875 int tmpCards[5];
1876 tmpCards[0] = static_cast<int>(netDealFlop.flopcard1());
1877 tmpCards[1] = static_cast<int>(netDealFlop.flopcard2());
1878 tmpCards[2] = static_cast<int>(netDealFlop.flopcard3());
1879 tmpCards[3] = tmpCards[4] = 0;
1880 curGame->getCurrentHand()->getBoard()->setMyCards(tmpCards);
1881 curGame->getCurrentHand()->getBoard()->collectPot();
1882 curGame->getCurrentHand()->setPreviousPlayerID(-1);
1883
1884 client->GetGui().logDealBoardCardsMsg(GAME_STATE_FLOP, tmpCards[0], tmpCards[1], tmpCards[2], tmpCards[3], tmpCards[4]);
1885 client->GetClientLog()->setCurrentRound(GAME_STATE_FLOP);
1886 client->GetClientLog()->logBoardCards(tmpCards);
1887 client->GetGui().refreshGameLabels(GAME_STATE_FLOP);
1888 client->GetGui().refreshPot();
1889 client->GetGui().refreshSet();
1890 client->GetGui().dealBeRoCards(1);
1891 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_DealTurnCardMessage) {
1892 const DealTurnCardMessage &netDealTurn = tmpPacket->GetMsg()->dealturncardmessage();
1893
1894 int tmpCards[5];
1895 curGame->getCurrentHand()->getBoard()->getMyCards(tmpCards);
1896 tmpCards[3] = static_cast<int>(netDealTurn.turncard());
1897 curGame->getCurrentHand()->getBoard()->setMyCards(tmpCards);
1898 curGame->getCurrentHand()->getBoard()->collectPot();
1899 curGame->getCurrentHand()->setPreviousPlayerID(-1);
1900
1901 client->GetGui().logDealBoardCardsMsg(GAME_STATE_TURN, tmpCards[0], tmpCards[1], tmpCards[2], tmpCards[3], tmpCards[4]);
1902 client->GetClientLog()->setCurrentRound(GAME_STATE_TURN);
1903 client->GetClientLog()->logBoardCards(tmpCards);
1904 client->GetGui().refreshGameLabels(GAME_STATE_TURN);
1905 client->GetGui().refreshPot();
1906 client->GetGui().refreshSet();
1907 client->GetGui().dealBeRoCards(2);
1908 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_DealRiverCardMessage) {
1909 const DealRiverCardMessage &netDealRiver = tmpPacket->GetMsg()->dealrivercardmessage();
1910
1911 int tmpCards[5];
1912 curGame->getCurrentHand()->getBoard()->getMyCards(tmpCards);
1913 tmpCards[4] = static_cast<int>(netDealRiver.rivercard());
1914 curGame->getCurrentHand()->getBoard()->setMyCards(tmpCards);
1915 curGame->getCurrentHand()->getBoard()->collectPot();
1916 curGame->getCurrentHand()->setPreviousPlayerID(-1);
1917
1918 client->GetGui().logDealBoardCardsMsg(GAME_STATE_RIVER, tmpCards[0], tmpCards[1], tmpCards[2], tmpCards[3], tmpCards[4]);
1919 client->GetClientLog()->setCurrentRound(GAME_STATE_RIVER);
1920 client->GetClientLog()->logBoardCards(tmpCards);
1921 client->GetGui().refreshGameLabels(GAME_STATE_RIVER);
1922 client->GetGui().refreshPot();
1923 client->GetGui().refreshSet();
1924 client->GetGui().dealBeRoCards(3);
1925 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_AllInShowCardsMessage) {
1926 const AllInShowCardsMessage &netAllInShow = tmpPacket->GetMsg()->allinshowcardsmessage();
1927
1928 curGame->getCurrentHand()->setAllInCondition(true);
1929
1930 // Set player numbers using the game start data slots.
1931 unsigned numPlayers = netAllInShow.playersallin_size();
1932 // Request player info for players if needed.
1933 for (unsigned i = 0; i < numPlayers; i++) {
1934 const AllInShowCardsMessage::PlayerAllIn &p = netAllInShow.playersallin(i);
1935
1936 boost::shared_ptr<PlayerInterface> tmpPlayer = curGame->getPlayerByUniqueId(p.playerid());
1937 if (!tmpPlayer)
1938 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1939
1940 int tmpCards[2];
1941 tmpCards[0] = static_cast<int>(p.allincard1());
1942 tmpCards[1] = static_cast<int>(p.allincard2());
1943 tmpPlayer->setMyCards(tmpCards);
1944 }
1945 client->GetGui().flipHolecardsAllIn();
1946 if(curGame->getCurrentHand()->getCurrentRound()<GAME_STATE_RIVER) {
1947 client->GetClientLog()->logHoleCardsHandName(
1948 curGame->getActivePlayerList()
1949 );
1950 }
1951 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_EndOfHandHideCardsMessage) {
1952 const EndOfHandHideCardsMessage &hideCards = tmpPacket->GetMsg()->endofhandhidecardsmessage();
1953 curGame->getCurrentHand()->getBoard()->collectPot();
1954 // Reset player sets
1955 ResetPlayerSets(*curGame);
1956 client->GetGui().refreshPot();
1957 client->GetGui().refreshSet();
1958 // Synchronize with GUI.
1959 client->GetGui().waitForGuiUpdateDone();
1960
1961 // End of Hand, but keep cards hidden.
1962 boost::shared_ptr<PlayerInterface> tmpPlayer = curGame->getPlayerByUniqueId(hideCards.playerid());
1963 if (!tmpPlayer)
1964 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
1965
1966 tmpPlayer->setMyCash(hideCards.playermoney());
1967 tmpPlayer->setLastMoneyWon(hideCards.moneywon());
1968 list<unsigned> winnerList;
1969 winnerList.push_back(tmpPlayer->getMyUniqueID());
1970
1971 curGame->getCurrentHand()->getBoard()->setPot(0);
1972 curGame->getCurrentHand()->getBoard()->setWinners(winnerList);
1973
1974 // logging
1975 client->GetClientLog()->logHandWinner(curGame->getActivePlayerList(), tmpPlayer->getMyCardsValueInt(), winnerList);
1976
1977 client->GetGui().postRiverRunAnimation1();
1978
1979 // Wait for next Hand.
1980 client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_SERVER_HAND_END);
1981 client->SetState(ClientStateWaitHand::Instance());
1982
1983 // logging
1984 client->GetClientLog()->logPlayerSitsOut(curGame->getActivePlayerList());
1985 client->GetClientLog()->logGameWinner(curGame->getActivePlayerList());
1986 client->GetClientLog()->logAfterHand();
1987 } else if (tmpPacket->GetMsg()->messagetype() == PokerTHMessage::Type_EndOfHandShowCardsMessage) {
1988 const EndOfHandShowCardsMessage &showCards = tmpPacket->GetMsg()->endofhandshowcardsmessage();
1989
1990 curGame->getCurrentHand()->getBoard()->collectPot();
1991 // Reset player sets
1992 ResetPlayerSets(*curGame);
1993 client->GetGui().refreshPot();
1994 client->GetGui().refreshSet();
1995 // Synchronize with GUI.
1996 client->GetGui().waitForGuiUpdateDone();
1997
1998 // End of Hand, show cards.
1999 list<unsigned> winnerList;
2000 list<unsigned> showList;
2001 int highestValueOfCards = 0;
2002 unsigned numResults = showCards.playerresults_size();
2003 // Request player info for players if needed.
2004 for (unsigned i = 0; i < numResults; i++) {
2005 const PlayerResult &r = showCards.playerresults(i);
2006
2007 boost::shared_ptr<PlayerInterface> tmpPlayer = curGame->getPlayerByUniqueId(r.playerid());
2008 if (!tmpPlayer)
2009 throw ClientException(__FILE__, __LINE__, ERR_NET_UNKNOWN_PLAYER_ID, 0);
2010
2011 int tmpCards[2];
2012 int bestHandPos[5];
2013 tmpCards[0] = static_cast<int>(r.resultcard1());
2014 tmpCards[1] = static_cast<int>(r.resultcard2());
2015 tmpPlayer->setMyCards(tmpCards);
2016 for (int num = 0; num < 5; num++) {
2017 bestHandPos[num] = r.besthandposition(num);
2018 }
2019 if (r.has_cardsvalue()) {
2020 tmpPlayer->setMyCardsValueInt(r.cardsvalue());
2021 }
2022 tmpPlayer->setMyBestHandPosition(bestHandPos);
2023 if (tmpPlayer->getMyCardsValueInt() > highestValueOfCards)
2024 highestValueOfCards = tmpPlayer->getMyCardsValueInt();
2025 tmpPlayer->setMyCash(r.playermoney());
2026 tmpPlayer->setLastMoneyWon(r.moneywon());
2027 if (r.moneywon())
2028 winnerList.push_back(r.playerid());
2029 showList.push_back(r.playerid());
2030 }
2031
2032 curGame->getCurrentHand()->setCurrentRound(GAME_STATE_POST_RIVER);
2033 client->GetClientLog()->setCurrentRound(GAME_STATE_POST_RIVER);
2034 curGame->getCurrentHand()->getCurrentBeRo()->setHighestCardsValue(highestValueOfCards);
2035 curGame->getCurrentHand()->getBoard()->setPot(0);
2036 curGame->getCurrentHand()->getBoard()->setWinners(winnerList);
2037 curGame->getCurrentHand()->getBoard()->setPlayerNeedToShowCards(showList);
2038
2039 // logging
2040 client->GetClientLog()->logHoleCardsHandName(curGame->getActivePlayerList());
2041 client->GetClientLog()->logHandWinner(curGame->getActivePlayerList(), highestValueOfCards, winnerList);
2042
2043 client->GetGui().postRiverRunAnimation1();
2044
2045 // Wait for next Hand.
2046 client->GetCallback().SignalNetClientGameInfo(MSG_NET_GAME_CLIENT_HAND_END);
2047 client->SetState(ClientStateWaitHand::Instance());
2048
2049 // logging
2050 client->GetClientLog()->logPlayerSitsOut(curGame->getActivePlayerList());
2051 client->GetClientLog()->logGameWinner(curGame->getActivePlayerList());
2052 client->GetClientLog()->logAfterHand();
2053 }
2054
2055 // Synchronize with GUI.
2056 client->GetGui().waitForGuiUpdateDone();
2057 }
2058
2059 void
ResetPlayerActions(Game & curGame)2060 ClientStateRunHand::ResetPlayerActions(Game &curGame)
2061 {
2062 // Reset player actions
2063 PlayerListIterator i = curGame.getSeatsList()->begin();
2064 PlayerListIterator end = curGame.getSeatsList()->end();
2065
2066 while (i != end) {
2067 int action = (*i)->getMyAction();
2068 if (action != 1 && action != 6)
2069 (*i)->setMyAction(PLAYER_ACTION_NONE);
2070 (*i)->setMySetNull();
2071 ++i;
2072 }
2073 }
2074
2075 void
ResetPlayerSets(Game & curGame)2076 ClientStateRunHand::ResetPlayerSets(Game &curGame)
2077 {
2078 PlayerListIterator i = curGame.getSeatsList()->begin();
2079 PlayerListIterator end = curGame.getSeatsList()->end();
2080 while (i != end) {
2081 (*i)->setMySetNull();
2082 ++i;
2083 }
2084 }
2085
2086 //-----------------------------------------------------------------------------
2087
2088 ClientStateFinal &
Instance()2089 ClientStateFinal::Instance()
2090 {
2091 static ClientStateFinal state;
2092 return state;
2093 }
2094