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