1 /* $Id: clientcommunicator.cpp,v 1.11.4.1 2006/03/26 08:24:22 chfreund Exp $ */
2 
3 #include "clientcommunicator.hpp"
4 #include "message.hpp"
5 #include "serverentry.hpp"
6 #include "serverconnectiondirect.hpp"
7 #include "serverconnectiontcp.hpp"
8 #include "serverconnectiontcpudp.hpp"
9 #include "tcpconnection.hpp"
10 #include "server.hpp"
11 #include "client.hpp"
12 #include "avatar.hpp"
13 #include "string.hpp"
14 
ClientCommunicator(Client * client)15 ClientCommunicator::ClientCommunicator( Client* client )
16 	: m_client( client ), m_serverConnection( 0 ),
17 	  m_lastMessage( 0 ), m_world( 0 ), m_frameTimer( 0 ),
18 	  m_waitingPlayer( 0 ) {
19 	m_mutex = SDL_CreateMutex();
20 	m_cond = SDL_CreateCond();
21 
22 	m_baitSocket = SDLNet_UDP_Open( 0 );
23 	ASSERT( m_baitSocket,
24 	        "ClientCommunicator::ClientCommunicator: could not create bait socket (%s)\n",
25 	        SDLNet_GetError() );
26 
27 	m_baitPacket = SDLNet_AllocPacket( 200 );
28 	ASSERT( m_baitPacket,
29 	        "ClientCommunicator::ClientCommunicator: could not allocate bait packet (%s)\n",
30 	        SDLNet_GetError() );
31 /*	m_baitPacket->data[0] = 0xb8;
32 	m_baitPacket->data[1] = 0xb8;*/
33 }
34 
~ClientCommunicator()35 ClientCommunicator::~ClientCommunicator() {
36 	// TODO: should the following be deleted here?
37 	//  - world
38 	//  - players
39 
40 	if ( m_frameTimer )
41 		SDL_RemoveTimer( m_frameTimer );
42 	if ( m_serverConnection )
43 		delete m_serverConnection;
44 	if ( m_lastMessage )
45 		delete m_lastMessage;
46 
47 	SDL_DestroyMutex( m_mutex );
48 	SDL_DestroyCond( m_cond );
49 
50 	SDLNet_UDP_Close( m_baitSocket );
51 	SDLNet_FreePacket( m_baitPacket );
52 }
53 
openConnection(ServerEntry & server)54 bool ClientCommunicator::openConnection( ServerEntry& server ) {
55 	switch ( server.type ) {
56 	case ServerEntry::DIRECT: {
57 		LOG( 2 ) INFO( "ClientCommunicator::openConnection: opening connection to local server\n" );
58 		DirectServerEntry& directEntry =
59 			static_cast<DirectServerEntry&>( server );
60 		ServerConnectionDirect* directConnection =
61 			new ServerConnectionDirect( directEntry.server );
62 		m_serverConnection = directConnection;
63 		m_clientID = directConnection->openConnection();
64 		m_serverConnection->setClient( m_client );
65 		return true;
66 		break;
67 	}
68 	case ServerEntry::REMOTE:
69 /*		LOG( 2 ) INFO( "ClientCommunicator::openConnection: opening connection to remote server\n" );
70 		RemoteServerEntry& remoteEntry =
71 			static_cast<RemoteServerEntry&>( server );
72 		ServerConnectionTCPUDP* remoteConnection =
73 			new ServerConnectionTCPUDP( remoteEntry );
74 		m_serverConnection = remoteConnection;
75 		m_clientID = remoteConnection->openConnection();*/
76 		m_serverConnection = m_serverConnectionFactory.openConnection( server );
77 		if ( m_serverConnection ) {
78 			m_clientID = m_serverConnection->getClientID();
79 			m_serverConnection->setClient( m_client );
80 			return true;
81 		}
82 		break;
83 	}
84 	return false;
85 }
86 
setActive()87 void ClientCommunicator::setActive() {
88 	ASSERT( m_serverConnection,
89 	        "ClientCommunicator::setActive: no connection\n" );
90 	// request the world from the server
91 	RequestMessage requestMessage;
92 	requestMessage.request = Message::WORLD;
93 	m_client->initializeConnectProgress();
94 	m_serverConnection->setProgressListener( this );
95 	m_serverConnection->sendMessage( &requestMessage );
96 	// get the answer
97 	Message* message = 0;
98 	// TODO: timeout?
99 	while ( !( message = m_serverConnection->popMessage() ) )
100 		;
101 	m_serverConnection->setProgressListener( 0 );
102 	m_client->hideConnectProgress();
103 	ASSERT( message->type == Message::WORLD,
104 	        "ClientCommunicator::setActive: expected WORLD message\n" );
105 	WorldMessage* worldMessage = static_cast<WorldMessage*>( message );
106 	m_world = worldMessage->world;
107 	m_world->setMessageSink( m_client );
108 	m_world->incrementFrame();
109 	if ( m_serverConnection->getType() == ServerEntry::REMOTE ) {
110 		// create a surface from the pixel values in the map
111 		m_world->optimizeForClient( m_client->getVideo().getScreen()->format, SDL_SWSURFACE );
112 	}
113 	m_frameTimer = SDL_AddTimer( 40, ClientCommunicator::frameHandler, this );
114 }
115 
closeConnection()116 void ClientCommunicator::closeConnection() {
117 	DBG( 2 ) INFO( "ClientCommunicator::closeConnection: start\n" );
118 	SDL_mutexP( m_mutex );
119 	SDL_RemoveTimer( m_frameTimer );
120 	m_serverConnection->closeConnection();
121 	delete m_serverConnection;
122 	m_serverConnection = 0;
123 	delete m_lastMessage;
124 	m_lastMessage = 0;
125 	m_player.clear();
126 	m_playerInput.clear();
127 	delete m_world;
128 	m_world = 0;
129 	SDL_mutexV( m_mutex );
130 	DBG( 2 ) INFO( "ClientCommunicator::closeConnection: finish\n" );
131 }
132 
getPlayerNumber(Player * player) const133 Uint8 ClientCommunicator::getPlayerNumber( Player* player ) const {
134 	for ( Uint8 i = 0; i < m_player.size(); i++ ) {
135 		if ( m_player[i] == player )
136 			return i;
137 	}
138 
139 	return 255;
140 }
141 
addPlayer(Player * player,PlayerInput * input)142 void ClientCommunicator::addPlayer( Player* player, PlayerInput* input ) {
143 	SDL_mutexP( m_mutex );
144 	// determine local player number
145 	Uint8 localPlayerNumber = m_player.size();
146 	// add input object
147 	m_playerInput.push_back( input );
148 
149 	// create message for the server
150 	AddPlayerMessage* addPlayerMessage = new AddPlayerMessage();
151 	addPlayerMessage->clientID = m_clientID;
152 	addPlayerMessage->localPlayerNumber = localPlayerNumber;
153 	addPlayerMessage->player = player;
154 	// send the message to the server
155 	m_serverConnection->sendMessage( addPlayerMessage );
156 
157 	// wait for the server answer to arrive
158 	m_waitingPlayer = player;
159 	while ( true ) {
160 		Message* message = m_lastMessage;
161 		m_lastMessage = 0;
162 		if ( !message || message->type != Message::ADD_PLAYER ) {
163 			SDL_CondWait( m_cond, m_mutex );
164 		}
165 		else {
166 			ASSERT( message && message->type == Message::ADD_PLAYER,
167 			        "ClientCommunicator::addPlayer: oops, wrong answer\n" );
168 			AddPlayerMessage* addPlayerMessage2 =
169 				static_cast<AddPlayerMessage*>( message );
170 			ASSERT( addPlayerMessage2->clientID == m_clientID,
171 			        "ClientCommunicator::addPlayer: received answer refers not to local player\n" );
172 			DBG( 2 ) INFO( "ClientCommunicator::addPlayer: adding player to list of local players (%5.2f)\n",
173 			               SDL_GetTicks() / 1000.0 );
174 			// add player to local list
175 			m_player.push_back( player );
176 			delete message;
177 			break;
178 		}
179 	}
180 	SDL_mutexV( m_mutex );
181 
182 	// here or elsewhere?
183 	delete addPlayerMessage;
184 }
185 
removePlayer(Player * player)186 void ClientCommunicator::removePlayer( Player* player ) {
187 	SDL_mutexP( m_mutex );
188 	// determine local player number
189 	Uint8 playerNumber = getPlayerNumber( player );
190 	// remove player from local list
191 	m_player.erase( m_player.begin() + playerNumber );
192 	SDL_mutexV( m_mutex );
193 
194 	// create message for the server
195 	Message* message = new RemovePlayerMessage( playerNumber );
196 	// send the message to the server
197 	m_serverConnection->sendMessage( message );
198 	// here or elsewhere?
199 	delete message;
200 }
201 
processEvents()202 void ClientCommunicator::processEvents() {
203 	SDL_mutexP( m_mutex );
204 	if ( m_serverConnection ) {
205 		// create a new message containing the events for all local players
206 		EventMessage* message = new EventMessage( m_player.size() );
207 
208 		// Collect events from all players
209 		for ( unsigned int playerNumber = 0; playerNumber < m_player.size();
210 			playerNumber++ ) {
211 			message->event[playerNumber] =
212 				m_playerInput[playerNumber]->getEvent();
213 		}
214 
215 		// send the message to the server
216 		m_serverConnection->sendMessage( message );
217 		// here or elsewhere?
218 		delete message;
219 	}
220 	else {
221 		DBG( 4 ) INFO( "ClientCommunicator::processEvents: called although "
222 		               "no connection is present\n" );
223 	}
224 	SDL_mutexV( m_mutex );
225 }
226 
processEchos()227 void ClientCommunicator::processEchos() {
228 	SDL_mutexP( m_mutex );
229 	if ( m_serverConnection ) {
230 		// TODO: walk through message queue and look for echo messages
231 
232 		// if we do not use a direct connection we have to update the
233 		// world by ourselves
234 		if ( m_serverConnection->getType() != ServerEntry::DIRECT ) {
235 			EchoMessage* echoMessage = 0;
236 			do {
237 				echoMessage =
238 					m_serverConnection->getEchoMessage( m_world->getFrame() );
239 				if ( !echoMessage )
240 					break;
241 
242 				// check if we have to process waiting messages before the next frame
243 				if ( echoMessage->numberMessages > 0 ) {
244 					DBG( 4 ) INFO( "ClientCommunicator::processEchos: before processing echo for frame %d we have to wait for %d messages (%5.2f)\n", echoMessage->frame, echoMessage->numberMessages, SDL_GetTicks() / 1000.0 );
245 					Uint32 index = 0;
246 					// SDL_mutexP( m_mutex );
247 					while ( index < echoMessage->numberMessages ) {
248 						Message* message = m_serverConnection->peekMessage();
249 						if ( !message ) {
250 							continue;
251 						}
252 						switch ( message->type ) {
253 						case Message::ADD_PLAYER: {
254 							DBG( 4 ) INFO( "ClientCommunicator::processEchos: handling ADD_PLAYER message (%5.2f)\n",
255 										SDL_GetTicks() / 1000.0 );
256 							AddPlayerMessage* addPlayerMessage =
257 								static_cast<AddPlayerMessage*>( message );
258 							if ( addPlayerMessage->frame >= echoMessage->frame )
259 								continue;
260 							// add the player to the world
261 							m_serverConnection->popMessage();
262 							if ( addPlayerMessage->clientID != m_clientID ) {
263 								Player* player = addPlayerMessage->player;
264 								if ( m_serverConnection->getType() != ServerEntry::DIRECT )
265 									m_world->addPlayer( addPlayerMessage->player );
266 								// inform client about joining player
267 								m_client->joinPlayer( player );
268 								delete message;
269 							}
270 							else {
271 								ASSERT( m_waitingPlayer, "ClientCommunicator::processEchos: a player for this client arrived but none is waiting to be added\n" );
272 								Player* player = addPlayerMessage->player;
273 								*m_waitingPlayer = *player;
274 								if ( m_serverConnection->getType() != ServerEntry::DIRECT )
275 									m_world->addPlayer( m_waitingPlayer );
276 								// inform client about joining player
277 								m_client->joinPlayer( m_waitingPlayer );
278 								// if the added player is from this client, wake up the function
279 								// that waits for this answer
280 								m_lastMessage = message;
281 								// SDL_mutexV( m_mutex );
282 								SDL_CondSignal( m_cond );
283 								// SDL_mutexP( m_mutex );
284 							}
285 							// increase message counter for this frame
286 							index++;
287 							break;
288 						}
289 						case Message::REMOVE_PLAYER: {
290 							DBG( 4 ) INFO( "ClientCommunicator::processEchos: handling REMOVE_PLAYER message\n" );
291 							RemovePlayerMessage* removePlayerMessage =
292 								static_cast<RemovePlayerMessage*>( message );
293 							m_serverConnection->popMessage();
294 							// get player from world
295 							Player* player = m_world->getPlayerByID( removePlayerMessage->playerNumber );
296 							m_world->removePlayer( removePlayerMessage->playerNumber );
297 							// inform client
298 							m_client->leavePlayer( player );
299 							// cleanup
300 							delete player;
301 							delete removePlayerMessage;
302 							// increase message counter for this frame
303 							index++;
304 							break;
305 						}
306 						case Message::CHAT: {
307 							ChatMessage* chatMessage =
308 								static_cast<ChatMessage*>( message );
309 							m_serverConnection->popMessage();
310 							DBG( 2 ) INFO( "ClientCommunicator::processEchos: handling CHAT message\n" );
311 							m_client->showMessage( chatMessage->message, chatMessage->color );
312 							delete chatMessage;
313 							index++;
314 							break;
315 						}
316 						default:
317 							// TODO: ignore all other packets?
318 							break;
319 						}
320 					}
321 					// SDL_mutexV( m_mutex );
322 				}
323 
324 				DBG( 5 ) INFO( "ClientCommunicator::processEchos: processing ECHO message for frame %d (random = %d, %x)\n", echoMessage->frame, echoMessage->randomCounter, echoMessage->event[0].get() );
325 
326 				ASSERT( echoMessage->randomCounter == m_world->getRandom().getCounter(),
327 						"ClientCommunicator::processEchos: lost synchronicity before frame %d (client: %d, server: %d, messages: %d)\n",
328 						echoMessage->frame, m_world->getRandom().getCounter(), echoMessage->randomCounter,
329 						echoMessage->numberMessages );
330 
331 				m_world->applyEvents( echoMessage );
332 				m_world->doTimestep();
333 				m_world->incrementFrame();
334 				m_client->signalDisplayCond();
335 				delete echoMessage;
336 
337 				// update all players (better outside while loop?)
338 				// especially bots
339 				for ( unsigned int i = 0; i < m_player.size(); i++ )
340 					m_player[i]->update();
341 			} while ( echoMessage );
342 		}
343 
344 		// Check if connection is still valid
345 		if ( !m_serverConnection->isValid() ) {
346 			SDL_mutexV( m_mutex );
347 			m_client->lostConnection();
348 			return;
349 		}
350 	}
351 	else {
352 		DBG( 4 ) INFO( "ClientCommunicator::processEchos: called although "
353 		               "no connection is present\n" );
354 	}
355 	SDL_mutexV( m_mutex );
356 }
357 
sendChatMessage(String & message,const SDL_Color & color)358 void ClientCommunicator::sendChatMessage( String& message, const SDL_Color& color ) {
359 	ChatMessage chatMessage;
360 	chatMessage.message = message;
361 	chatMessage.color = color;
362 	LOG( 2 ) INFO( "ClientCommunicator::sendChatMessage: send chat message to server\n" );
363 	m_serverConnection->sendMessage( &chatMessage );
364 }
365 
lookForServers()366 std::vector<ServerEntry*> ClientCommunicator::lookForServers() {
367 	std::vector<ServerEntry*> servers;
368 
369 	BaitMessage baitMessage;
370 	m_baitPacket->len = baitMessage.getSerializeBufferSize();
371 	Uint8* bufferPointer = m_baitPacket->data;
372 	baitMessage.serialize( bufferPointer );
373 	LOG( 2 ) INFO( "ClientCommunicator::lookForServers: sending bait packets to local subnet\n" );
374 	// one broadcast to all reachable subnets
375 	SDLNet_ResolveHost( &m_baitPacket->address, "255.255.255.255", 0xb8b8 );
376 	CHECK( SDLNet_UDP_Send( m_baitSocket, -1, m_baitPacket ) == 1,
377 	       "ClientCommunicator::lookForServers: could not send bait packet to local subnet (%s)\n",
378 	       SDLNet_GetError() );
379 	// check localhost
380 	SDLNet_ResolveHost( &m_baitPacket->address, "127.0.0.1", 0xb8b8 );
381 	CHECK( SDLNet_UDP_Send( m_baitSocket, -1, m_baitPacket ) == 1,
382 	       "ClientCommunicator::lookForServers: could not send bait packet to localhost (%s)\n",
383 	       SDLNet_GetError() );
384 	// TODO: check direct connection
385 
386 	SDL_Delay( 500 );
387 
388 	while ( SDLNet_UDP_Recv( m_baitSocket, m_baitPacket ) == 1 ) {
389 		LOG( 2 ) INFO( "ClientCommunicator::lookForServers: received bait answer (len: %i) from %i.%i.%i.%i:%i\n",
390 		               m_baitPacket->len, DECODE_IP( m_baitPacket->address.host ),
391 		               m_baitPacket->address.port );
392 		Message headerMessage;
393 		bufferPointer = m_baitPacket->data;
394 		headerMessage.deserialize( bufferPointer );
395 		if ( headerMessage.type == Message::BAIT_ANSWER ) {
396 			BaitAnswerMessage answerMessage( headerMessage );
397 			answerMessage.deserializeData( bufferPointer );
398 			if ( answerMessage.magicData == 0xb8b8 ) {
399 				LOG( 2 ) INFO( "ClientCommunicator::lookForServers: valid server response\n" );
400 /*				Uint16 serverPort;
401 				Uint8* dataPointer = reinterpret_cast<Uint8*>( m_baitPacket->data + 2 );
402 				Serialize<Uint16>::deserialize( dataPointer, serverPort );*/
403 				// create server entry
404 				IPaddress serverAddress;
405 				serverAddress.host = m_baitPacket->address.host;
406 				serverAddress.port = answerMessage.serverPort;
407 				RemoteServerEntry* serverEntry = new RemoteServerEntry( serverAddress );
408 				serverEntry->theme = answerMessage.theme;
409 				serverEntry->numberPlayers = answerMessage.numberPlayers;
410 				servers.push_back( serverEntry );
411 			}
412 		}
413 	}
414 
415 	return servers;
416 }
417 
getServerInfo()418 InfoMessage* ClientCommunicator::getServerInfo() {
419 	if ( !m_serverConnection )
420 		return 0;
421 
422 	RequestMessage requestMessage;
423 	requestMessage.request = Message::INFO;
424 	m_serverConnection->sendMessage( &requestMessage );
425 
426 	Message* message = 0;
427 	// TODO: timeout
428 	while ( !( message = m_serverConnection->popMessage() ) )
429 		;
430 	ASSERT( message->type == Message::INFO,
431 	        "ClientCommunicator::getServerInfo: expected INFO message, got type %d\n", message->type );
432 
433 	return static_cast<InfoMessage*>( message );
434 }
435 
recvProgress(Sint32 size,Sint32 received)436 void ClientCommunicator::recvProgress( Sint32 size, Sint32 received ) {
437 	m_client->updateConnectProgress( size, received );
438 }
439 
frameHandler(Uint32 interval,void * data)440 Uint32 ClientCommunicator::frameHandler( Uint32 interval, void* data ) {
441 	static Uint32 counter = 0;
442 	static int tick_reference = SDL_GetTicks();
443 	Uint32 ticksBefore = SDL_GetTicks();
444 	ClientCommunicator* communicator =
445 		static_cast<ClientCommunicator*>( data );
446 	communicator->processEvents();
447 	communicator->processEchos();
448 	Uint32 ticksAfter = SDL_GetTicks();
449 	Uint32 duration = ticksAfter - ticksBefore;
450 	Uint32 newInterval = ( duration >= 40 ) ? 1 : 40 - duration;
451 	DBG( 5 ) {
452 		int ticks = SDL_GetTicks();
453 		counter++;
454 		if ( ticks - tick_reference >= 1000 ) {
455 			INFO( "ClientCommunicator::frameHandler: called with %4.1f fps\n",
456 			      counter * 1.0 );
457 			counter = 0;
458 			tick_reference = ticks;
459 		}
460 	}
461 	return newInterval;
462 }
463