1 /*=============================================================================
2 Blobby Volley 2
3 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de)
4 Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de)
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 =============================================================================*/
20 
21 /* header include */
22 
23 /* includes */
24 #include <algorithm>
25 #include <iostream>
26 #include <ctime>
27 
28 #include <boost/lexical_cast.hpp>
29 #include <boost/scoped_array.hpp>
30 #include <boost/make_shared.hpp>
31 
32 #include "raknet/RakClient.h"
33 #include "raknet/RakServer.h"
34 #include "raknet/PacketEnumerations.h"
35 #include "raknet/GetTime.h"
36 
37 #include "NetworkState.h"
38 #include "NetworkMessage.h"
39 #include "TextManager.h"
40 #include "ReplayRecorder.h"
41 #include "DuelMatch.h"
42 #include "IMGUI.h"
43 #include "SoundManager.h"
44 #include "LocalInputSource.h"
45 #include "UserConfig.h"
46 #include "FileExceptions.h"
47 #include "GenericIO.h"
48 #include "FileRead.h"
49 #include "FileWrite.h"
50 #include "MatchEvents.h"
51 #include "SpeedController.h"
52 #include "server/DedicatedServer.h"
53 #include "LobbyState.h"
54 #include "InputManager.h"
55 
56 
57 /* implementation */
NetworkGameState(boost::shared_ptr<RakClient> client)58 NetworkGameState::NetworkGameState( boost::shared_ptr<RakClient> client):
59 	 GameState(new DuelMatch(true, DEFAULT_RULES_FILE)),
60 	 mClient( client ),
61 	 mWinningPlayer(NO_PLAYER),
62 	 mNetworkState(WAITING_FOR_OPPONENT),
63 	 mWaitingForReplay(false),
64 	 mSelectedChatmessage(0),
65 	 mChatCursorPosition(0),
66 	 mChattext("")
67 {
68 	boost::shared_ptr<IUserConfigReader> config = IUserConfigReader::createUserConfigReader("config.xml");
69 	mOwnSide = (PlayerSide)config->getInteger("network_side");
70 	mUseRemoteColor = config->getBool("use_remote_color");
71 	mLocalInput.reset(new LocalInputSource(mOwnSide));
72 	mLocalInput->setMatch(mMatch.get());
73 
74 	/// \todo why do we need this here?
75 	RenderManager::getSingleton().redraw();
76 
77 	// game is not started until two players are connected
78 	mMatch->pause();
79 
80 	// load/init players
81 
82 	if(mOwnSide == LEFT_PLAYER)
83 	{
84 		PlayerIdentity localplayer = config->loadPlayerIdentity(LEFT_PLAYER, true);
85 		PlayerIdentity remoteplayer = config->loadPlayerIdentity(RIGHT_PLAYER, true);
86 		mLocalPlayer = &mMatch->getPlayer( LEFT_PLAYER );
87 		mRemotePlayer = &mMatch->getPlayer( RIGHT_PLAYER );
88 		mMatch->setPlayers( localplayer, remoteplayer );
89 	}
90 	 else
91 	{
92 		PlayerIdentity localplayer = config->loadPlayerIdentity(RIGHT_PLAYER, true);
93 		PlayerIdentity remoteplayer = config->loadPlayerIdentity(LEFT_PLAYER, true);
94 		mLocalPlayer = &mMatch->getPlayer( RIGHT_PLAYER );
95 		mRemotePlayer = &mMatch->getPlayer( LEFT_PLAYER );
96 		mMatch->setPlayers( remoteplayer, localplayer );
97 	}
98 
99 	mRemotePlayer->setName("");
100 }
101 
~NetworkGameState()102 NetworkGameState::~NetworkGameState()
103 {
104 	mClient->Disconnect(50);
105 }
106 
step_impl()107 void NetworkGameState::step_impl()
108 {
109 	IMGUI& imgui = IMGUI::getSingleton();
110 	RenderManager* rmanager = &RenderManager::getSingleton();
111 
112 	packet_ptr packet;
113 	while (packet = mClient->Receive())
114 	{
115 		switch(packet->data[0])
116 		{
117 			case ID_PHYSIC_UPDATE:
118 			{
119 				RakNet::BitStream stream((char*)packet->data, packet->length, false);
120 				int ival;
121 				stream.IgnoreBytes(1);	//ID_PHYSIC_UPDATE
122 				stream.IgnoreBytes(1);	//ID_TIMESTAMP
123 				stream.Read(ival);	//TODO: un-lag based on timestamp delta
124 				//printf("Physic packet received. Time: %d\n", ival);
125 				DuelMatchState ms;
126 				boost::shared_ptr<GenericIn> in = createGenericReader(&stream);
127 				in->generic<DuelMatchState> (ms);
128 				mMatch->setState(ms);
129 				break;
130 			}
131 			case ID_WIN_NOTIFICATION:
132 			{
133 				RakNet::BitStream stream((char*)packet->data, packet->length, false);
134 				stream.IgnoreBytes(1);	//ID_WIN_NOTIFICATION
135 				stream.Read((int&)mWinningPlayer);
136 
137 				// last point must not be added anymore, because
138 				// the score is also simulated local so it is already
139 				// right. under strange circumstances this need not
140 				// be true, but then the score is set to the correy value
141 				// by ID_BALL_RESET
142 
143 				mNetworkState = PLAYER_WON;
144 				break;
145 			}
146 			case ID_OPPONENT_DISCONNECTED:
147 			{
148 				// In this state, a leaving opponent would not be very surprising
149 				if (mNetworkState != PLAYER_WON)
150 					mNetworkState = OPPONENT_DISCONNECTED;
151 				break;
152 			}
153 			case ID_BALL_RESET:
154 			{
155 				PlayerSide servingPlayer;
156 				RakNet::BitStream stream((char*)packet->data, packet->length, false);
157 				stream.IgnoreBytes(1);	//ID_BALL_RESET
158 				stream.Read((int&)servingPlayer);
159 
160 				// read and set new score
161 				int nLeftScore;
162 				int nRightScore;
163 				int time;
164 				stream.Read(nLeftScore);
165 				stream.Read(nRightScore);
166 				stream.Read(time);
167 				mMatch->setScore(nLeftScore, nRightScore);
168 				mMatch->setServingPlayer(servingPlayer);
169 				// sync the clocks... normally, they should not differ
170 				mMatch->getClock().setTime(time);
171 
172 				/// \attention
173 				/// we can get a problem here:
174 				/// assume the packet informing about the game event which lead to this
175 				///	either BALL_GROUND_COLLISION or BALL_PLAYER_COLLISION got stalled
176 				/// and arrives at the same time time as this packet. Then we get the following behaviour:
177 				/// we set the score to the right value... the event causing the score to happen gets processed
178 				///  -> that player scores -> score is off!
179 				///
180 				/// i don't have a clean fix for this right now, so we'll have to live with a workaround for now
181 				/// we just order the game to reset all triggered events.
182 				mMatch->resetTriggeredEvents();
183 				/// \todo a good fix would involve ensuring we process all events in the right order
184 
185 
186 				break;
187 			}
188 			case ID_COLLISION:
189 			{
190 				int event;
191 				float intensity;
192 				RakNet::BitStream stream((char*)packet->data, packet->length, false);
193 				stream.IgnoreBytes(1);	//ID_COLLISION
194 				stream.Read(event);
195 				stream.Read(intensity);
196 
197 				mMatch->setLastHitIntensity(intensity);
198 				mMatch->trigger( event );
199 				break;
200 			}
201 			case ID_PAUSE:
202 				if (mNetworkState == PLAYING)
203 				{
204 					mNetworkState = PAUSING;
205 					mMatch->pause();
206 				}
207 				break;
208 			case ID_UNPAUSE:
209 				if (mNetworkState == PAUSING)
210 				{
211 					SDL_StopTextInput();
212 					mNetworkState = PLAYING;
213 					mMatch->unpause();
214 				}
215 				break;
216 			case ID_GAME_READY:
217 			{
218 				char charName[16];
219 				RakNet::BitStream stream((char*)packet->data, packet->length, false);
220 
221 				stream.IgnoreBytes(1);	// ignore ID_GAME_READY
222 
223 				// read gamespeed
224 				int speed;
225 				stream.Read(speed);
226 				SpeedController::getMainInstance()->setGameSpeed(speed);
227 
228 				// read playername
229 				stream.Read(charName, sizeof(charName));
230 
231 				// ensures that charName is null terminated
232 				charName[sizeof(charName)-1] = '\0';
233 
234 				// read colors
235 				int temp;
236 				stream.Read(temp);
237 				Color ncolor = temp;
238 
239 				mRemotePlayer->setName(charName);
240 
241 				setDefaultReplayName(mLocalPlayer->getName(), mRemotePlayer->getName());
242 
243 				// check whether to use remote player color
244 				if(mUseRemoteColor)
245 				{
246 					mRemotePlayer->setStaticColor(ncolor);
247 					RenderManager::getSingleton().redraw();
248 				}
249 
250 				// Workarround for SDL-Renderer
251 				// Hides the GUI when networkgame starts
252 				rmanager->redraw();
253 
254 				mNetworkState = PLAYING;
255 				// start game
256 				mMatch->unpause();
257 
258 				// game ready whistle
259 				SoundManager::getSingleton().playSound("sounds/pfiff.wav", ROUND_START_SOUND_VOLUME);
260 				break;
261 			}
262 			case ID_RULES_CHECKSUM:
263 			{
264 				RakNet::BitStream stream((char*)packet->data, packet->length, false);
265 
266 				stream.IgnoreBytes(1);	// ignore ID_RULES_CHECKSUM
267 
268 				int serverChecksum;
269 				stream.Read(serverChecksum);
270 				int ourChecksum = 0;
271 				if (serverChecksum != 0)
272 				{
273 					try
274 					{
275 						FileRead rulesFile("server_rules.lua");
276 						ourChecksum = rulesFile.calcChecksum(0);
277 						rulesFile.close();
278 					}
279 					catch( FileLoadException& ex )
280 					{
281 						// file doesn't exist - nothing to do here
282 					}
283 				}
284 
285 				RakNet::BitStream stream2;
286 				stream2.Write((unsigned char)ID_RULES);
287 				stream2.Write(bool(serverChecksum != 0 && serverChecksum != ourChecksum));
288 				mClient->Send(&stream2, HIGH_PRIORITY, RELIABLE_ORDERED, 0);
289 
290 				break;
291 			}
292 			case ID_RULES:
293 			{
294 				RakNet::BitStream stream((char*)packet->data, packet->length, false);
295 
296 				stream.IgnoreBytes(1);	// ignore ID_RULES
297 
298 				int rulesLength;
299 				stream.Read(rulesLength);
300 				if (rulesLength)
301 				{
302 					boost::shared_array<char>  rulesString( new char[rulesLength + 1] );
303 					stream.Read(rulesString.get(), rulesLength);
304 					// null terminate
305 					rulesString[rulesLength] = 0;
306 					FileWrite rulesFile("server_rules.lua");
307 					rulesFile.write(rulesString.get(), rulesLength);
308 					rulesFile.close();
309 					mMatch->setRules("server_rules.lua");
310 				}
311 				else
312 				{
313 					// either old server, or we have to use fallback ruleset
314 					mMatch->setRules( FALLBACK_RULES_NAME );
315 				}
316 
317 				break;
318 			}
319 			// status messages we don't care about
320 			case ID_REMOTE_DISCONNECTION_NOTIFICATION:
321 			case ID_REMOTE_CONNECTION_LOST:
322 			case ID_SERVER_STATUS:
323 			case ID_CHALLENGE:
324 			case ID_REMOTE_NEW_INCOMING_CONNECTION:
325 			case ID_REMOTE_EXISTING_CONNECTION:
326 				break;
327 			case ID_DISCONNECTION_NOTIFICATION:
328 			case ID_CONNECTION_LOST:
329 				if (mNetworkState != PLAYER_WON)
330 					mNetworkState = DISCONNECTED;
331 				break;
332 			case ID_NO_FREE_INCOMING_CONNECTIONS:
333 				mNetworkState = SERVER_FULL;
334 				break;
335 			case ID_CHAT_MESSAGE:
336 			{
337 				RakNet::BitStream stream((char*)packet->data, packet->length, false);
338 				stream.IgnoreBytes(1);	// ID_CHAT_MESSAGE
339 				// Insert Message in the log and focus the last element
340 				char message[31];
341 				stream.Read(message, sizeof(message));
342 				message[30] = '\0';
343 
344 				// Insert Message in the log and focus the last element
345 				mChatlog.push_back((std::string) message);
346 				mChatOrigin.push_back(false);
347 				mSelectedChatmessage = mChatlog.size() - 1;
348 				SoundManager::getSingleton().playSound("sounds/chat.wav", ROUND_START_SOUND_VOLUME);
349 				break;
350 			}
351 			case ID_REPLAY:
352 			{
353 				/// \todo we should take more action if server sends replay
354 				///		even if not requested!
355 				if(!mWaitingForReplay)
356 					break;
357 
358 				RakNet::BitStream stream = RakNet::BitStream((char*)packet->data, packet->length, false);
359 				stream.IgnoreBytes(1);	// ID_REPLAY
360 
361 				// read stream into a dummy replay recorder
362 				boost::shared_ptr<GenericIn> reader = createGenericReader( &stream );
363 				ReplayRecorder dummyRec;
364 				dummyRec.receive( reader );
365 				// and save that
366 				saveReplay(dummyRec);
367 
368 				// mWaitingForReplay will be set to false even if replay could not be saved because
369 				// the server won't send it again.
370 				mWaitingForReplay = false;
371 
372 				break;
373 			}
374 
375 			// we never do anything that should cause such a packet to be received!
376 			case ID_CONNECTION_REQUEST_ACCEPTED:
377 			case ID_CONNECTION_ATTEMPT_FAILED:
378 				assert( 0 );
379 				break;
380 
381 			case ID_BLOBBY_SERVER_PRESENT:
382 			{
383 				// this should only be called if we use the stay on server option
384 				RakNet::BitStream stream( packet->getStream() );
385 				stream.IgnoreBytes(1);	//ID_BLOBBY_SERVER_PRESENT
386 				ServerInfo info(stream,	mClient->PlayerIDToDottedIP(packet->playerId), packet->playerId.port);
387 
388 				if (packet->length == ServerInfo::BLOBBY_SERVER_PRESENT_PACKET_SIZE )
389 				{
390 					switchState(new LobbyState(info));
391 				}
392 				break;
393 			}
394 			default:
395 				printf("Received unknown Packet %d\n", packet->data[0]);
396 				std::cout<<packet->data<<"\n";
397 				break;
398 		}
399 	}
400 
401 	// does this generate any problems if we pause at the exact moment an event is set ( i.e. the ball hit sound
402 	// could be played in a loop)?
403 	presentGame();
404 	presentGameUI();
405 
406 	if (InputManager::getSingleton()->exit() && mNetworkState != PLAYING)
407 	{
408 		if(mNetworkState == PAUSING)
409 		{
410 			// end pause
411 			RakNet::BitStream stream;
412 			stream.Write((unsigned char)ID_UNPAUSE);
413 			mClient->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0);
414 		}
415 		else
416 		{
417 			switchState(new MainMenuState);
418 		}
419 	}
420 	else if (InputManager::getSingleton()->exit() && mSaveReplay)
421 	{
422 		mSaveReplay = false;
423 		IMGUI::getSingleton().resetSelection();
424 	}
425 	else if (mErrorMessage != "")
426 	{
427 		displayErrorMessageBox();
428 	}
429 	else if (mSaveReplay)
430 	{
431 		if ( displaySaveReplayPrompt() )
432 		{
433 
434 			// request replay from server
435 			RakNet::BitStream stream;
436 			stream.Write((unsigned char)ID_REPLAY);
437 			mClient->Send(&stream, LOW_PRIORITY, RELIABLE_ORDERED, 0);
438 
439 			mSaveReplay = false;
440 			mWaitingForReplay = true;
441 		}
442 	}
443 	else if (mWaitingForReplay)
444 	{
445 		imgui.doOverlay(GEN_ID, Vector2(150, 200), Vector2(650, 400));
446 		imgui.doText(GEN_ID, Vector2(190, 220), TextManager::RP_WAIT_REPLAY);
447 		if (imgui.doButton(GEN_ID, Vector2(440, 330), TextManager::LBL_CANCEL))
448 		{
449 			mSaveReplay = false;
450 			mWaitingForReplay = false;
451 			imgui.resetSelection();
452 		}
453 		imgui.doCursor();
454 	}
455 	else switch (mNetworkState)
456 	{
457 		case WAITING_FOR_OPPONENT:
458 		{
459 			imgui.doOverlay(GEN_ID, Vector2(100.0, 210.0),
460 					Vector2(700.0, 310.0));
461 			imgui.doText(GEN_ID, Vector2(150.0, 250.0),
462 					TextManager::GAME_WAITING);
463 			break;
464 		}
465 		case OPPONENT_DISCONNECTED:
466 		{
467 			imgui.doCursor();
468 			imgui.doOverlay(GEN_ID, Vector2(100.0, 210.0), Vector2(700.0, 390.0));
469 			imgui.doText(GEN_ID, Vector2(140.0, 240.0),	TextManager::GAME_OPP_LEFT);
470 
471 			if (imgui.doButton(GEN_ID, Vector2(230.0, 290.0), TextManager::LBL_OK))
472 			{
473 				switchState(new MainMenuState);
474 			}
475 
476 			if (imgui.doButton(GEN_ID, Vector2(350.0, 290.0), TextManager::RP_SAVE))
477 			{
478 				mSaveReplay = true;
479 				imgui.resetSelection();
480 			}
481 
482 			if (imgui.doButton(GEN_ID, Vector2(250.0, 340.0), TextManager::NET_STAY_ON_SERVER))
483 			{
484 				// Send a blobby server connection request
485 				RakNet::BitStream stream;
486 				stream.Write((unsigned char)ID_BLOBBY_SERVER_PRESENT);
487 				stream.Write(BLOBBY_VERSION_MAJOR);
488 				stream.Write(BLOBBY_VERSION_MINOR);
489 				mClient->Send(&stream, LOW_PRIORITY, RELIABLE_ORDERED, 0);
490 			}
491 			break;
492 		}
493 		case DISCONNECTED:
494 		{
495 			imgui.doCursor();
496 			imgui.doOverlay(GEN_ID, Vector2(100.0, 210.0),
497 					Vector2(700.0, 370.0));
498 			imgui.doText(GEN_ID, Vector2(120.0, 250.0),
499 					TextManager::NET_DISCONNECT);
500 			if (imgui.doButton(GEN_ID, Vector2(230.0, 320.0),
501 					TextManager::LBL_OK))
502 			{
503 				switchState(new MainMenuState);
504 			}
505 			if (imgui.doButton(GEN_ID, Vector2(350.0, 320.0), TextManager::RP_SAVE))
506 			{
507 				mSaveReplay = true;
508 				imgui.resetSelection();
509 			}
510 			break;
511 		}
512 		case SERVER_FULL:
513 		{
514 			imgui.doCursor();
515 			imgui.doOverlay(GEN_ID, Vector2(100.0, 210.0),Vector2(700.0, 370.0));
516 			imgui.doText(GEN_ID, Vector2(200.0, 250.0),	TextManager::NET_SERVER_FULL);
517 			if (imgui.doButton(GEN_ID, Vector2(350.0, 300.0), TextManager::LBL_OK))
518 			{
519 				switchState(new MainMenuState);
520 			}
521 			break;
522 		}
523 		case PLAYING:
524 		{
525 			mMatch->step();
526 
527 			mLocalInput->updateInput();
528 			PlayerInputAbs input = mLocalInput->getRealInput();
529 
530 			if (InputManager::getSingleton()->exit())
531 			{
532 				RakNet::BitStream stream;
533 				stream.Write((unsigned char)ID_PAUSE);
534 				mClient->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0);
535 			}
536 			RakNet::BitStream stream;
537 			stream.Write((unsigned char)ID_INPUT_UPDATE);
538 			stream.Write((unsigned char)ID_TIMESTAMP);	///! \todo do we really need this time stamps?
539 			stream.Write(RakNet::GetTime());
540 			input.writeTo(stream);
541 			mClient->Send(&stream, HIGH_PRIORITY, UNRELIABLE_SEQUENCED, 0);
542 			break;
543 		}
544 		case PLAYER_WON:
545 		{
546 			displayWinningPlayerScreen(mWinningPlayer);
547 			if (imgui.doButton(GEN_ID, Vector2(290, 360), TextManager::LBL_OK))
548 			{
549 				switchState(new MainMenuState());
550 			}
551 			if (imgui.doButton(GEN_ID, Vector2(380, 360), TextManager::RP_SAVE))
552 			{
553 				mSaveReplay = true;
554 				imgui.resetSelection();
555 			}
556 			break;
557 		}
558 		case PAUSING:
559 		{
560 			imgui.doOverlay(GEN_ID, Vector2(175, 20), Vector2(625, 175));
561 			imgui.doText(GEN_ID, Vector2(275, 35), TextManager::GAME_PAUSED);
562 			if (imgui.doButton(GEN_ID, Vector2(205, 95), TextManager::LBL_CONTINUE))
563 			{
564 				RakNet::BitStream stream;
565 				stream.Write((unsigned char)ID_UNPAUSE);
566 				mClient->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0);
567 			}
568 			// Chat
569 			imgui.doChatbox(GEN_ID, Vector2(10, 190), Vector2(790, 450), mChatlog, mSelectedChatmessage, mChatOrigin);
570 			if (imgui.doEditbox(GEN_ID, Vector2(30, 460), 30, mChattext, mChatCursorPosition, 0, true))
571 			{
572 
573 				// GUI-Hack, so that we can send messages
574 				if ((InputManager::getSingleton()->getLastActionKey() == "Return") && (mChattext != ""))
575 				{
576 					RakNet::BitStream stream;
577 					char message[31];
578 
579 					strncpy(message, mChattext.c_str(), sizeof(message));
580 					stream.Write((unsigned char)ID_CHAT_MESSAGE);
581 					stream.Write(message, sizeof(message));
582 					mClient->Send(&stream, LOW_PRIORITY, RELIABLE_ORDERED, 0);
583 					mChatlog.push_back(mChattext);
584 					mChatOrigin.push_back(true);
585 					mSelectedChatmessage = mChatlog.size() - 1;
586 					mChattext = "";
587 					mChatCursorPosition = 0;
588 					SoundManager::getSingleton().playSound("sounds/chat.wav", ROUND_START_SOUND_VOLUME);
589 				}
590 			}
591 			if (imgui.doButton(GEN_ID, Vector2(500, 95), TextManager::GAME_QUIT))
592 			{
593 				switchState(new MainMenuState);
594 			}
595 			if (imgui.doButton(GEN_ID, Vector2(285, 125), TextManager::RP_SAVE))
596 			{
597 				mSaveReplay = true;
598 				imgui.resetSelection();
599 			}
600 			imgui.doCursor();
601 		}
602 	}
603 }
604 
getStateName() const605 const char* NetworkGameState::getStateName() const
606 {
607 	return "NetworkGameState";
608 }
609 
610 // ---------------------------------------------------------------------------------------------------------------------------------
611 //	implementation of the local host state
612 // ----------------------------------------
613 
NetworkHostState()614 NetworkHostState::NetworkHostState() : mServer(  ), mClient( new RakClient ), mGameState(nullptr)
615 {
616 	// read config
617 	/// \todo we need read-only access here!
618 	UserConfig config;
619 	config.loadFile("config.xml");
620 	PlayerSide localSide = (PlayerSide)config.getInteger("network_side");
621 
622 	// load/init players
623 	if(localSide == LEFT_PLAYER)
624 	{
625 		mLocalPlayer = config.loadPlayerIdentity(LEFT_PLAYER, true);
626 	}
627 	 else
628 	{
629 		mLocalPlayer = config.loadPlayerIdentity(RIGHT_PLAYER, true);
630 	}
631 
632 	ServerInfo info( mLocalPlayer.getName().c_str());
633 	std::string rulesfile = config.getString("rules");
634 
635 	mServer.reset( new DedicatedServer(info, rulesfile, 4));
636 
637 	// connect to server
638 	if (!mClient->Connect(info.hostname, info.port, 0, 0, RAKNET_THREAD_SLEEP_TIME))
639 		throw( std::runtime_error(std::string("Could not connect to server ") + info.hostname) );
640 
641 
642 }
643 
~NetworkHostState()644 NetworkHostState::~NetworkHostState()
645 {
646 	delete mGameState;
647 }
648 
step_impl()649 void NetworkHostState::step_impl()
650 {
651 	packet_ptr packet;
652 	if( mGameState == nullptr )
653 	{
654 		while (packet = mClient->Receive())
655 		{
656 			switch(packet->data[0])
657 			{
658 				// as soon as we are connected to the server
659 				case ID_CONNECTION_REQUEST_ACCEPTED:
660 				{
661 					// ----------------------------------------------------
662 					// Send ENTER SERVER packet
663 					RakNet::BitStream stream;
664 					stream.Write((unsigned char)ID_ENTER_SERVER);
665 
666 					// Send preferred side
667 					stream.Write( mLocalPlayer.getPreferredSide() );
668 
669 					// Send playername
670 					char myname[16];
671 					strncpy(myname, mLocalPlayer.getName().c_str(), sizeof(myname));
672 					stream.Write(myname, sizeof(myname));
673 
674 					// send color settings
675 					stream.Write(mLocalPlayer.getStaticColor().toInt());
676 
677 					mClient->Send(&stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0);
678 
679 					// Send ENTER GAME packet
680 
681 					RakNet::BitStream stream2;
682 					stream2.Write((char)ID_CHALLENGE);
683 					auto writer = createGenericWriter(&stream2);
684 					writer->generic<PlayerID>( UNASSIGNED_PLAYER_ID );
685 
686 					mClient->Send(&stream2, HIGH_PRIORITY, RELIABLE_ORDERED, 0);
687 
688 					mGameState = new NetworkGameState(mClient);
689 
690 					break;
691 				}
692 				case ID_SERVER_STATUS:
693 					{
694 
695 					}
696 					break;
697 				default:
698 					std::cout << "Unknown packet " << int(packet->data[0]) << " received\n";
699 			}
700 		}
701 	}
702 
703 	if(mServer->hasActiveGame())
704 	{
705 		mServer->allowNewPlayers(false);
706 	}
707 
708 	mServer->processPackets();
709 
710 	/// \todo make this gamespeed independent
711 	mLobbyCounter++;
712 	if(mLobbyCounter % (750 /*10s*/) == 0 )
713 	{
714 		mServer->updateLobby();
715 	}
716 
717 	mServer->updateGames();
718 
719 	if( mGameState )
720 		mGameState->step_impl();
721 }
722 
getStateName() const723 const char* NetworkHostState::getStateName() const
724 {
725 	return "NetworkHostState";
726 }
727 
728 // definition of syslog for client hosted games
syslog(int pri,const char * format,...)729 void syslog(int pri, const char* format, ...)
730 {
731 	// do nothing?
732 }
733 
734 // debug counters
735 int SWLS_PacketCount;
736 int SWLS_Connections;
737 int SWLS_Games;
738 int SWLS_GameSteps;
739 int SWLS_ServerEntered;
740