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 /* State of a network game. */
32 
33 #ifndef _SERVERGAMESTATE_H_
34 #define _SERVERGAMESTATE_H_
35 
36 #include <boost/asio.hpp>
37 #include <playerdata.h>
38 #include <net/sessionmanager.h>
39 
40 
41 #ifdef _MSC_VER
42 #pragma warning(push)
43 #pragma warning(disable : 4250)
44 #endif
45 
46 #define SERVER_INITIAL_STATE	ServerGameStateInit
47 
48 class Game;
49 class ServerGame;
50 class PlayerInterface;
51 class ServerCallback;
52 
53 class ServerGameState
54 {
55 public:
56 	virtual ~ServerGameState();
57 	virtual void Enter(boost::shared_ptr<ServerGame> server) = 0;
58 	virtual void Exit(boost::shared_ptr<ServerGame> server) = 0;
59 
60 	virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> server) = 0;
61 	virtual void NotifySessionRemoved(boost::shared_ptr<ServerGame> server) = 0;
62 
63 	// Handling of a new player session.
64 	virtual void HandleNewPlayer(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session) = 0;
65 	// Handling of a new spectator session.
66 	virtual void HandleNewSpectator(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session) = 0;
67 
68 	// Main processing function of the current state.
69 	virtual void ProcessPacket(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet) = 0;
70 };
71 
72 // Abstract State: Receiving.
73 class AbstractServerGameStateReceiving : public ServerGameState
74 {
75 public:
76 	virtual ~AbstractServerGameStateReceiving();
77 
78 	// Globally handle packets which are allowed in all running states.
79 	// Calls InternalProcess if packet has not been processed.
80 	virtual void ProcessPacket(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
81 
82 	static boost::shared_ptr<NetPacket> CreateNetPacketPlayerJoined(unsigned gameId, const PlayerData &playerData);
83 	static boost::shared_ptr<NetPacket> CreateNetPacketSpectatorJoined(unsigned gameId, const PlayerData &playerData);
84 	static boost::shared_ptr<NetPacket> CreateNetPacketJoinGameAck(const ServerGame &server, const PlayerData &playerData, bool spectateOnly);
85 	static boost::shared_ptr<NetPacket> CreateNetPacketHandStart(const ServerGame &server);
86 
87 	static void AcceptNewSession(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session, bool spectateOnly);
88 
89 protected:
90 
91 	virtual void InternalProcessPacket(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet) = 0;
92 };
93 
94 // State: Initialization.
95 class ServerGameStateInit : public AbstractServerGameStateReceiving
96 {
97 public:
98 	static ServerGameStateInit &Instance();
99 	virtual void Enter(boost::shared_ptr<ServerGame> server);
100 	virtual void Exit(boost::shared_ptr<ServerGame> server);
101 
102 	virtual ~ServerGameStateInit();
103 
104 	virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> server);
105 	virtual void NotifySessionRemoved(boost::shared_ptr<ServerGame> server);
106 
107 	virtual void HandleNewPlayer(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session);
108 	virtual void HandleNewSpectator(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session);
109 
110 protected:
111 	ServerGameStateInit();
112 
113 	void RegisterAdminTimer(boost::shared_ptr<ServerGame> server);
114 	void UnregisterAdminTimer(boost::shared_ptr<ServerGame> server);
115 	void RegisterAutoStartTimer(boost::shared_ptr<ServerGame> server);
116 	void UnregisterAutoStartTimer(boost::shared_ptr<ServerGame> server);
117 	void TimerAutoStart(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
118 	void TimerAdminWarning(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
119 	void TimerAdminTimeout(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
120 	void SendStartEvent(ServerGame &server, bool fillWithComputerPlayers);
121 
122 	virtual void InternalProcessPacket(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
123 
124 private:
125 	static ServerGameStateInit s_state;
126 };
127 
128 // Wait for Ack of start event and start game.
129 class ServerGameStateStartGame : public AbstractServerGameStateReceiving
130 {
131 public:
132 	static ServerGameStateStartGame &Instance();
133 	virtual void Enter(boost::shared_ptr<ServerGame> server);
134 	virtual void Exit(boost::shared_ptr<ServerGame> server);
135 
136 	virtual ~ServerGameStateStartGame();
137 
NotifyGameAdminChanged(boost::shared_ptr<ServerGame>)138 	virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> /*server*/) {}
NotifySessionRemoved(boost::shared_ptr<ServerGame>)139 	virtual void NotifySessionRemoved(boost::shared_ptr<ServerGame> /*server*/) {}
140 	virtual void HandleNewPlayer(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session);
141 	virtual void HandleNewSpectator(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session);
142 
143 protected:
144 	ServerGameStateStartGame();
145 
146 	virtual void InternalProcessPacket(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
147 	void TimerTimeout(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
148 	void DoStart(boost::shared_ptr<ServerGame> server);
149 
150 private:
151 	static ServerGameStateStartGame s_state;
152 };
153 
154 class AbstractServerGameStateRunning : public AbstractServerGameStateReceiving
155 {
156 public:
157 	virtual ~AbstractServerGameStateRunning();
158 
159 	virtual void HandleNewPlayer(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session);
160 	virtual void HandleNewSpectator(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session);
161 
162 protected:
163 	virtual void InternalProcessPacket(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
164 };
165 
166 // State: Within hand.
167 class ServerGameStateHand : public AbstractServerGameStateRunning
168 {
169 public:
170 	static ServerGameStateHand &Instance();
171 	virtual void Enter(boost::shared_ptr<ServerGame> server);
172 	virtual void Exit(boost::shared_ptr<ServerGame> server);
173 
174 	virtual ~ServerGameStateHand();
175 
NotifyGameAdminChanged(boost::shared_ptr<ServerGame>)176 	virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> /*server*/) {}
NotifySessionRemoved(boost::shared_ptr<ServerGame>)177 	virtual void NotifySessionRemoved(boost::shared_ptr<ServerGame> /*server*/) {}
178 
179 protected:
180 	ServerGameStateHand();
181 
182 	virtual void InternalProcessPacket(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
183 	void TimerLoop(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
184 	void EngineLoop(boost::shared_ptr<ServerGame> server);
185 	void TimerShowCards(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
186 	void TimerComputerAction(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
187 	void TimerNextHand(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
188 	void TimerNextGame(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server, unsigned winnerPlayerId);
189 	int GetDealCardsDelaySec(ServerGame &server);
190 	static void StartNewHand(boost::shared_ptr<ServerGame> server);
191 	static void CheckPlayerTimeouts(boost::shared_ptr<ServerGame> server);
192 	static void ReactivatePlayers(boost::shared_ptr<ServerGame> server);
193 	static void InitRejoiningPlayers(boost::shared_ptr<ServerGame> server);
194 	static void InitNewSpectators(boost::shared_ptr<ServerGame> server);
195 	static void PerformRejoin(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session);
196 	static void SendGameData(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session);
197 
198 private:
199 	static ServerGameStateHand s_state;
200 
201 	friend class ServerGameStateStartGame;
202 	friend class ServerGameStateWaitNextHand;
203 };
204 
205 // State: Wait for a player action.
206 class ServerGameStateWaitPlayerAction : public AbstractServerGameStateRunning
207 {
208 public:
209 	static ServerGameStateWaitPlayerAction &Instance();
210 	virtual void Enter(boost::shared_ptr<ServerGame> server);
211 	virtual void Exit(boost::shared_ptr<ServerGame> server);
212 
213 	virtual ~ServerGameStateWaitPlayerAction();
214 
NotifyGameAdminChanged(boost::shared_ptr<ServerGame>)215 	virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> /*server*/) {}
NotifySessionRemoved(boost::shared_ptr<ServerGame>)216 	virtual void NotifySessionRemoved(boost::shared_ptr<ServerGame> /*server*/) {}
217 
218 protected:
219 	ServerGameStateWaitPlayerAction();
220 
221 	virtual void InternalProcessPacket(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
222 	void TimerTimeout(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
223 
224 private:
225 	static ServerGameStateWaitPlayerAction s_state;
226 };
227 
228 // State: Wait for the next hand.
229 class ServerGameStateWaitNextHand : public AbstractServerGameStateRunning
230 {
231 public:
232 	static ServerGameStateWaitNextHand &Instance();
233 	virtual void Enter(boost::shared_ptr<ServerGame> server);
234 	virtual void Exit(boost::shared_ptr<ServerGame> server);
235 
236 	virtual ~ServerGameStateWaitNextHand();
237 
NotifyGameAdminChanged(boost::shared_ptr<ServerGame>)238 	virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> /*server*/) {}
NotifySessionRemoved(boost::shared_ptr<ServerGame>)239 	virtual void NotifySessionRemoved(boost::shared_ptr<ServerGame> /*server*/) {}
240 
241 protected:
242 	ServerGameStateWaitNextHand();
243 
244 	virtual void InternalProcessPacket(boost::shared_ptr<ServerGame> server, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
245 	void TimerTimeout(const boost::system::error_code &ec, boost::shared_ptr<ServerGame> server);
246 
247 private:
248 	static ServerGameStateWaitNextHand s_state;
249 };
250 
251 class ServerGameStateFinal : public ServerGameState
252 {
253 public:
254 	static ServerGameStateFinal &Instance();
255 
~ServerGameStateFinal()256 	virtual ~ServerGameStateFinal() {}
Enter(boost::shared_ptr<ServerGame>)257 	virtual void Enter(boost::shared_ptr<ServerGame> /*server*/) {}
Exit(boost::shared_ptr<ServerGame>)258 	virtual void Exit(boost::shared_ptr<ServerGame> /*server*/) {}
259 
NotifyGameAdminChanged(boost::shared_ptr<ServerGame>)260 	virtual void NotifyGameAdminChanged(boost::shared_ptr<ServerGame> /*server*/) {}
NotifySessionRemoved(boost::shared_ptr<ServerGame>)261 	virtual void NotifySessionRemoved(boost::shared_ptr<ServerGame> /*server*/) {}
262 
263 	// Handling of a new session.
HandleNewPlayer(boost::shared_ptr<ServerGame>,boost::shared_ptr<SessionData>)264 	virtual void HandleNewPlayer(boost::shared_ptr<ServerGame> /*server*/, boost::shared_ptr<SessionData> /*session*/) {}
HandleNewSpectator(boost::shared_ptr<ServerGame>,boost::shared_ptr<SessionData>)265 	virtual void HandleNewSpectator(boost::shared_ptr<ServerGame> /*server*/, boost::shared_ptr<SessionData> /*session*/) {}
266 
267 	// Main processing function of the current state.
ProcessPacket(boost::shared_ptr<ServerGame>,boost::shared_ptr<SessionData>,boost::shared_ptr<NetPacket>)268 	virtual void ProcessPacket(boost::shared_ptr<ServerGame> /*server*/, boost::shared_ptr<SessionData> /*session*/, boost::shared_ptr<NetPacket> /*packet*/) {}
269 
270 protected:
ServerGameStateFinal()271 	ServerGameStateFinal() {}
272 
273 private:
274 	static ServerGameStateFinal s_state;
275 };
276 
277 #ifdef _MSC_VER
278 #pragma warning(pop)
279 #endif
280 
281 #endif
282