fixed ignoring clicks on global animations after executing event actions
[rocksndiamonds.git] / src / network.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // network.c
10 // ============================================================================
11
12 #include "libgame/platform.h"
13
14 #if defined(NETWORK_AVALIABLE)
15
16 #include <signal.h>
17 #include <sys/time.h>
18
19 #include "main.h"
20
21 #include "libgame/libgame.h"
22
23 #include "network.h"
24 #include "netserv.h"
25 #include "game.h"
26 #include "tape.h"
27 #include "files.h"
28 #include "tools.h"
29 #include "screens.h"
30
31 struct NetworkClientPlayerInfo
32 {
33   byte nr;
34   char name[MAX_PLAYER_NAME_LEN + 1];
35   struct NetworkClientPlayerInfo *next;
36 };
37
38 static struct NetworkClientPlayerInfo first_player =
39 {
40   0,
41   EMPTY_PLAYER_NAME,
42   NULL
43 };
44
45 /* server stuff */
46
47 static TCPsocket sfd;           /* server socket */
48 static SDLNet_SocketSet rfds;   /* socket set */
49
50 static byte realbuffer[512];
51 static byte readbuffer[MAX_BUFFER_SIZE], writbuffer[MAX_BUFFER_SIZE];
52 static byte *buffer = realbuffer + 4;
53 static int nread = 0, nwrite = 0;
54 static boolean stop_network_game = FALSE;
55
56 static void SendBufferToServer(int size)
57 {
58   if (!options.network)
59     return;
60
61   realbuffer[0] = realbuffer[1] = realbuffer[2] = 0;
62   realbuffer[3] = (byte)size;
63   buffer[0] = 0;
64
65   if (nwrite + 4 + size >= MAX_BUFFER_SIZE)
66     Error(ERR_EXIT, "internal error: network send buffer overflow");
67
68   memcpy(writbuffer + nwrite, realbuffer, 4 + size);
69   nwrite += 4 + size;
70
71   /* directly send the buffer to the network server */
72   SDLNet_TCP_Send(sfd, writbuffer, nwrite);
73   nwrite = 0;
74 }
75
76 struct NetworkClientPlayerInfo *getNetworkPlayer(int player_nr)
77 {
78   struct NetworkClientPlayerInfo *player = NULL;
79
80   for (player = &first_player; player; player = player->next)
81     if (player->nr == player_nr)
82       break;
83
84   if (player == NULL)   /* should not happen */
85     Error(ERR_EXIT, "protocol error: reference to non-existing player %d",
86           player_nr);
87
88   return player;
89 }
90
91 char *getNetworkPlayerName(int player_nr)
92 {
93   struct NetworkClientPlayerInfo *player;
94
95   if (player_nr == 0)
96     return("the network game server");
97   else if (player_nr == first_player.nr)
98     return("you");
99   else
100     for (player = &first_player; player; player = player->next)
101       if (player->nr == player_nr && strlen(player->name) > 0)
102         return(player->name);
103
104   return(EMPTY_PLAYER_NAME);
105 }
106
107 static void StartNetworkServer(int port)
108 {
109   static int p;
110
111   p = port;
112 #if defined(TARGET_SDL2)
113   server_thread = SDL_CreateThread(NetworkServerThread,
114                                    "NetworkServerThread", &p);
115 #else
116   server_thread = SDL_CreateThread(NetworkServerThread, &p);
117 #endif
118   network_server = TRUE;
119 }
120
121 boolean ConnectToServer(char *hostname, int port)
122 {
123   IPaddress ip;
124   int i;
125
126   if (port == 0)
127     port = DEFAULT_SERVER_PORT;
128
129   rfds = SDLNet_AllocSocketSet(1);
130
131   if (hostname)
132   {
133     SDLNet_ResolveHost(&ip, hostname, port);
134     if (ip.host == INADDR_NONE)
135       Error(ERR_EXIT, "cannot locate host '%s'", hostname);
136   }
137   else
138   {
139     SDLNet_Write32(0x7f000001, &ip.host);       /* 127.0.0.1 */
140     SDLNet_Write16(port, &ip.port);
141   }
142
143   sfd = SDLNet_TCP_Open(&ip);
144
145   if (sfd)
146   {
147     SDLNet_TCP_AddSocket(rfds, sfd);
148     return TRUE;
149   }
150   else
151   {
152     printf("SDLNet_TCP_Open(): %s\n", SDLNet_GetError());
153   }
154
155   if (hostname)                 /* connect to specified server failed */
156     return FALSE;
157
158   printf("No rocksndiamonds server on localhost -- starting up one ...\n");
159   StartNetworkServer(port);
160
161   /* wait for server to start up and try connecting several times */
162   for (i = 0; i < 6; i++)
163   {
164     Delay(500);                 /* wait 500 ms == 0.5 seconds */
165
166     if ((sfd = SDLNet_TCP_Open(&ip)))           /* connected */
167     {
168       SDLNet_TCP_AddSocket(rfds, sfd);
169       return TRUE;
170     }
171   }
172
173   /* when reaching this point, connect to newly started server has failed */
174   return FALSE;
175 }
176
177 void SendToServer_PlayerName(char *player_name)
178 {
179   int len_player_name = strlen(player_name);
180
181   buffer[1] = OP_PLAYER_NAME;
182   memcpy(&buffer[2], player_name, len_player_name);
183   SendBufferToServer(2 + len_player_name);
184   Error(ERR_NETWORK_CLIENT, "you set your player name to \"%s\"", player_name);
185 }
186
187 void SendToServer_ProtocolVersion()
188 {
189   buffer[1] = OP_PROTOCOL_VERSION;
190   buffer[2] = PROTOCOL_VERSION_1;
191   buffer[3] = PROTOCOL_VERSION_2;
192   buffer[4] = PROTOCOL_VERSION_3;
193
194   SendBufferToServer(5);
195 }
196
197 void SendToServer_NrWanted(int nr_wanted)
198 {
199   buffer[1] = OP_NUMBER_WANTED;
200   buffer[2] = nr_wanted;
201
202   SendBufferToServer(3);
203 }
204
205 void SendToServer_StartPlaying()
206 {
207   unsigned int new_random_seed = InitRND(level.random_seed);
208
209   int dummy = 0;                /* !!! HAS NO MEANING ANYMORE !!! */
210                                 /* the name of the level must be enough */
211
212   buffer[1] = OP_START_PLAYING;
213   buffer[2] = (byte)(level_nr >> 8);
214   buffer[3] = (byte)(level_nr & 0xff);
215   buffer[4] = (byte)(dummy >> 8);
216   buffer[5] = (byte)(dummy & 0xff);
217
218   buffer[6] = (unsigned char)((new_random_seed >> 24) & 0xff);
219   buffer[7] = (unsigned char)((new_random_seed >> 16) & 0xff);
220   buffer[8] = (unsigned char)((new_random_seed >>  8) & 0xff);
221   buffer[9] = (unsigned char)((new_random_seed >>  0) & 0xff);
222
223   strcpy((char *)&buffer[10], leveldir_current->identifier);
224
225   SendBufferToServer(10 + strlen(leveldir_current->identifier) + 1);
226 }
227
228 void SendToServer_PausePlaying()
229 {
230   buffer[1] = OP_PAUSE_PLAYING;
231
232   SendBufferToServer(2);
233 }
234
235 void SendToServer_ContinuePlaying()
236 {
237   buffer[1] = OP_CONTINUE_PLAYING;
238
239   SendBufferToServer(2);
240 }
241
242 void SendToServer_StopPlaying(int cause_for_stopping)
243 {
244   buffer[1] = OP_STOP_PLAYING;
245   buffer[2] = cause_for_stopping;
246
247   SendBufferToServer(3);
248 }
249
250 void SendToServer_MovePlayer(byte player_action)
251 {
252   buffer[1] = OP_MOVE_PLAYER;
253   buffer[2] = player_action;
254
255   SendBufferToServer(3);
256 }
257
258 static void Handle_OP_BAD_PROTOCOL_VERSION()
259 {
260   Error(ERR_WARN, "protocol version mismatch");
261   Error(ERR_EXIT, "server expects %d.%d.x instead of %d.%d.%d",
262         buffer[2], buffer[3],
263         PROTOCOL_VERSION_1, PROTOCOL_VERSION_2, PROTOCOL_VERSION_3);
264 }
265
266 static void Handle_OP_YOUR_NUMBER()
267 {
268   int new_client_nr = buffer[2];
269   int new_index_nr = new_client_nr - 1;
270   struct PlayerInfo *old_local_player = local_player;
271   struct PlayerInfo *new_local_player = &stored_player[new_index_nr];
272
273   printf("OP_YOUR_NUMBER: %d\n", buffer[0]);
274   first_player.nr = new_client_nr;
275
276   if (old_local_player != new_local_player)
277   {
278     /* set relevant player settings and change to new player */
279
280     local_player = new_local_player;
281
282     old_local_player->connected_locally = FALSE;
283     new_local_player->connected_locally = TRUE;
284
285     old_local_player->connected_network = FALSE;
286     new_local_player->connected_network = TRUE;
287   }
288
289   if (first_player.nr > MAX_PLAYERS)
290     Error(ERR_EXIT, "sorry, more than %d players not allowed", MAX_PLAYERS);
291
292   Error(ERR_NETWORK_CLIENT, "you get client # %d", new_client_nr);
293 }
294
295 static void Handle_OP_NUMBER_WANTED()
296 {
297   int client_nr_wanted = buffer[2];
298   int old_client_nr = buffer[0];
299   int new_client_nr = buffer[3];
300   int old_index_nr = old_client_nr - 1;
301   int new_index_nr = new_client_nr - 1;
302   int index_nr_wanted = client_nr_wanted - 1;
303   struct PlayerInfo *old_player = &stored_player[old_index_nr];
304   struct PlayerInfo *new_player = &stored_player[new_index_nr];
305
306   printf("OP_NUMBER_WANTED: %d\n", buffer[0]);
307
308   if (new_client_nr == client_nr_wanted)        /* switching succeeded */
309   {
310     struct NetworkClientPlayerInfo *player;
311
312     if (old_client_nr != client_nr_wanted)      /* client's nr has changed */
313       Error(ERR_NETWORK_CLIENT, "client %d switches to # %d",
314             old_client_nr, new_client_nr);
315     else if (old_client_nr == first_player.nr)  /* local player keeps his nr */
316       Error(ERR_NETWORK_CLIENT, "keeping client # %d", new_client_nr);
317
318     if (old_client_nr != new_client_nr)
319     {
320       /* set relevant player settings and change to new player */
321
322       old_player->connected_network = FALSE;
323       new_player->connected_network = TRUE;
324     }
325
326     player = getNetworkPlayer(old_client_nr);
327     player->nr = new_client_nr;
328
329     if (old_player == local_player)             /* local player switched */
330     {
331       local_player = new_player;
332
333       old_player->connected_locally = FALSE;
334       new_player->connected_locally = TRUE;
335     }
336   }
337   else if (old_client_nr == first_player.nr)    /* failed -- local player? */
338   {
339     char request[100];
340
341     sprintf(request, "Sorry! Player %d already exists! You are player %d!",
342             index_nr_wanted + 1, new_index_nr + 1);
343
344     Request(request, REQ_CONFIRM);
345
346     Error(ERR_NETWORK_CLIENT, "cannot switch -- you keep client # %d",
347           new_client_nr);
348   }
349 }
350
351 static void Handle_OP_PLAYER_NAME(unsigned int len)
352 {
353   struct NetworkClientPlayerInfo *player;
354   int player_nr = (int)buffer[0];
355
356   printf("OP_PLAYER_NAME: %d\n", player_nr);
357   player = getNetworkPlayer(player_nr);
358   buffer[len] = 0;
359   Error(ERR_NETWORK_CLIENT, "client %d calls itself \"%s\"",
360         buffer[0], &buffer[2]);
361   strncpy(player->name, (char *)&buffer[2], MAX_PLAYER_NAME_LEN);
362 }
363
364 static void Handle_OP_PLAYER_CONNECTED()
365 {
366   struct NetworkClientPlayerInfo *player, *last_player = NULL;
367   int new_client_nr = (int)buffer[0];
368   int new_index_nr = new_client_nr - 1;
369
370   printf("OP_PLAYER_CONNECTED: %d\n", new_client_nr);
371   Error(ERR_NETWORK_CLIENT, "new client %d connected", new_client_nr);
372
373   for (player = &first_player; player; player = player->next)
374   {
375     if (player->nr == new_client_nr)
376       Error(ERR_EXIT, "multiplayer server sent duplicate player id");
377
378     last_player = player;
379   }
380
381   last_player->next = player =
382     checked_malloc(sizeof(struct NetworkClientPlayerInfo));
383   player->nr = new_client_nr;
384   player->name[0] = '\0';
385   player->next = NULL;
386
387   stored_player[new_index_nr].connected_network = TRUE;
388 }
389
390 static void Handle_OP_PLAYER_DISCONNECTED()
391 {
392   struct NetworkClientPlayerInfo *player, *player_disconnected;
393   int player_nr = (int)buffer[0];
394   int index_nr = player_nr - 1;
395
396   printf("OP_PLAYER_DISCONNECTED: %d\n", player_nr);
397   player_disconnected = getNetworkPlayer(player_nr);
398   Error(ERR_NETWORK_CLIENT, "client %d (%s) disconnected",
399         player_nr, getNetworkPlayerName(buffer[0]));
400
401   for (player = &first_player; player; player = player->next)
402     if (player->next == player_disconnected)
403       player->next = player_disconnected->next;
404   free(player_disconnected);
405
406   stored_player[index_nr].connected_locally = FALSE;
407   stored_player[index_nr].connected_network = FALSE;
408 }
409
410 static void Handle_OP_START_PLAYING()
411 {
412   LevelDirTree *new_leveldir;
413   int new_level_nr;
414   unsigned int new_random_seed;
415   char *new_leveldir_identifier;
416
417   new_level_nr = (buffer[2] << 8) + buffer[3];
418   new_random_seed =
419     (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | (buffer[9]);
420   new_leveldir_identifier = (char *)&buffer[10];
421
422   new_leveldir = getTreeInfoFromIdentifier(leveldir_first,
423                                            new_leveldir_identifier);
424   if (new_leveldir == NULL)
425   {
426     Error(ERR_WARN, "no such level identifier: '%s'", new_leveldir_identifier);
427
428     new_leveldir = leveldir_first;
429     Error(ERR_WARN, "using default level set: '%s'", new_leveldir->identifier);
430   }
431
432   printf("OP_START_PLAYING: %d\n", buffer[0]);
433   Error(ERR_NETWORK_CLIENT,
434         "client %d starts game [level %d from level identifier '%s']\n",
435         buffer[0], new_level_nr, new_leveldir->identifier);
436
437   leveldir_current = new_leveldir;
438   level_nr = new_level_nr;
439
440   TapeErase();
441   LoadTape(level_nr);
442   LoadLevel(level_nr);
443
444   StartGameActions(FALSE, setup.autorecord, new_random_seed);
445 }
446
447 static void Handle_OP_PAUSE_PLAYING()
448 {
449   printf("OP_PAUSE_PLAYING: %d\n", buffer[0]);
450   Error(ERR_NETWORK_CLIENT, "client %d pauses game", buffer[0]);
451
452   tape.pausing = TRUE;
453   DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0);
454 }
455
456 static void Handle_OP_CONTINUE_PLAYING()
457 {
458   printf("OP_CONTINUE_PLAYING: %d\n", buffer[0]);
459   Error(ERR_NETWORK_CLIENT, "client %d continues game", buffer[0]);
460
461   tape.pausing = FALSE;
462   DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
463 }
464
465 static void Handle_OP_STOP_PLAYING()
466 {
467   printf("OP_STOP_PLAYING: %d [%d]\n", buffer[0], buffer[2]);
468   Error(ERR_NETWORK_CLIENT, "client %d stops game [%d]", buffer[0], buffer[2]);
469
470   if (game_status == GAME_MODE_PLAYING)
471   {
472     if (buffer[2] == NETWORK_STOP_BY_PLAYER)
473       Request("Network game stopped by player!", REQ_CONFIRM);
474     else if (buffer[2] == NETWORK_STOP_BY_ERROR)
475       Request("Network game stopped due to internal error!", REQ_CONFIRM);
476     else
477       Request("Network game stopped!", REQ_CONFIRM);
478   }
479
480   SetGameStatus(GAME_MODE_MAIN);
481
482   DrawMainMenu();
483 }
484
485 static void Handle_OP_MOVE_PLAYER(unsigned int len)
486 {
487   int server_frame_counter;
488   int i;
489
490   if (!network_playing)
491     return;
492
493   server_frame_counter =
494     (buffer[2] << 24) | (buffer[3] << 16) | (buffer[4] << 8) | (buffer[5]);
495
496   if (server_frame_counter != FrameCounter)
497   {
498     Error(ERR_INFO, "client and servers frame counters out of sync");
499     Error(ERR_INFO, "frame counter of client is %d", FrameCounter);
500     Error(ERR_INFO, "frame counter of server is %d", server_frame_counter);
501     Error(ERR_INFO, "this should not happen -- please debug");
502
503     stop_network_game = TRUE;
504
505     return;
506   }
507
508   /* copy valid player actions */
509   for (i = 0; i < MAX_PLAYERS; i++)
510     stored_player[i].effective_action =
511       (i < len - 6 ? buffer[6 + i] : 0);
512
513   network_player_action_received = TRUE;
514 }
515
516 static void HandleNetworkingMessages()
517 {
518   unsigned int message_length;
519
520   stop_network_game = FALSE;
521
522   while (nread >= 4 && nread >= 4 + readbuffer[3])
523   {
524     message_length = readbuffer[3];
525     if (readbuffer[0] || readbuffer[1] || readbuffer[2])
526       Error(ERR_EXIT, "wrong network server line length");
527
528     memcpy(buffer, &readbuffer[4], message_length);
529     nread -= 4 + message_length;
530     memmove(readbuffer, readbuffer + 4 + message_length, nread);
531
532     switch (buffer[1])
533     {
534       case OP_BAD_PROTOCOL_VERSION:
535         Handle_OP_BAD_PROTOCOL_VERSION();
536         break;
537
538       case OP_YOUR_NUMBER:
539         Handle_OP_YOUR_NUMBER();
540         break;
541
542       case OP_NUMBER_WANTED:
543         Handle_OP_NUMBER_WANTED();
544         break;
545
546       case OP_PLAYER_NAME:
547         Handle_OP_PLAYER_NAME(message_length);
548         break;
549
550       case OP_PLAYER_CONNECTED:
551         Handle_OP_PLAYER_CONNECTED();
552         break;
553       
554       case OP_PLAYER_DISCONNECTED:
555         Handle_OP_PLAYER_DISCONNECTED();
556         break;
557
558       case OP_START_PLAYING:
559         Handle_OP_START_PLAYING();
560         break;
561
562       case OP_PAUSE_PLAYING:
563         Handle_OP_PAUSE_PLAYING();
564         break;
565
566       case OP_CONTINUE_PLAYING:
567         Handle_OP_CONTINUE_PLAYING();
568         break;
569
570       case OP_STOP_PLAYING:
571         Handle_OP_STOP_PLAYING();
572         break;
573
574       case OP_MOVE_PLAYER:
575         Handle_OP_MOVE_PLAYER(message_length);
576         break;
577
578       case OP_BROADCAST_MESSAGE:
579         printf("OP_BROADCAST_MESSAGE: %d\n", buffer[0]);
580         Error(ERR_NETWORK_CLIENT, "client %d sends message", buffer[0]);
581         break;
582     }
583   }
584
585   fflush(stdout);
586
587   /* in case of internal error, stop network game */
588   if (stop_network_game)
589     SendToServer_StopPlaying(NETWORK_STOP_BY_ERROR);
590 }
591
592 /* TODO */
593
594 void HandleNetworking()
595 {
596   int r = 0;
597
598   do
599   {
600     if ((r = SDLNet_CheckSockets(rfds, 1)) < 0)
601       Error(ERR_EXIT, "HandleNetworking(): SDLNet_CheckSockets() failed");
602
603     if (r > 0)
604     {
605       r = SDLNet_TCP_Recv(sfd, readbuffer + nread, 1);
606
607       if (r < 0)
608         Error(ERR_EXIT, "error reading from network server");
609
610       if (r == 0)
611         Error(ERR_EXIT, "connection to network server lost");
612
613       nread += r;
614
615       HandleNetworkingMessages();
616     }
617   }
618   while (r > 0);
619 }
620
621 #endif /* NETWORK_AVALIABLE */