bfe53c37c829e388dbf5ffb2bb197f9be720ef2e
[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 <signal.h>
13 #include <sys/time.h>
14
15 #include "libgame/libgame.h"
16
17 #include "network.h"
18 #include "netserv.h"
19 #include "main.h"
20 #include "game.h"
21 #include "tape.h"
22 #include "files.h"
23 #include "tools.h"
24 #include "screens.h"
25
26 struct NetworkClientPlayerInfo
27 {
28   byte nr;
29   char name[MAX_PLAYER_NAME_LEN + 1];
30   struct NetworkClientPlayerInfo *next;
31 };
32
33 static struct NetworkClientPlayerInfo first_player =
34 {
35   0,
36   EMPTY_PLAYER_NAME,
37   NULL
38 };
39
40 struct NetworkLevelFileInfo
41 {
42   char *leveldir_identifier;
43   struct LevelFileInfo file_info;
44   struct LevelFileInfo tmpl_info;
45   boolean use_network_level_files;
46   boolean use_custom_template;
47 };
48
49 /* server stuff */
50
51 static TCPsocket sfd;           /* TCP server socket */
52 static UDPsocket udp;           /* UDP server socket */
53 static SDLNet_SocketSet rfds;   /* socket set */
54
55 static struct NetworkBuffer *read_buffer = NULL;
56 static struct NetworkBuffer *write_buffer = NULL;
57
58 static boolean stop_network_game = FALSE;
59 static boolean stop_network_client = FALSE;
60 static char stop_network_client_message[MAX_OUTPUT_LINESIZE + 1];
61
62 static struct NetworkLevelFileInfo network_level;
63
64 static void DrawNetworkTextExt(char *message, int font_nr, boolean initialize)
65 {
66   static int xpos = 0, ypos = 0;
67   static int max_line_width = 0;
68   int font_width = getFontWidth(font_nr);
69   int font_height = getFontHeight(font_nr);
70   int ypos_1 = 120;
71   int ypos_2 = 150;
72
73   if (initialize)
74   {
75     if (game_status == GAME_MODE_LOADING)
76     {
77       max_line_width = WIN_XSIZE;
78
79       xpos = (max_line_width - getTextWidth(message, font_nr)) / 2;
80       ypos = ypos_1;
81
82       DrawText(xpos, ypos, message, font_nr);
83
84       xpos = 0;
85       ypos = ypos_2;
86     }
87     else
88     {
89       max_line_width = SXSIZE;
90
91       DrawTextSCentered(ypos_1, font_nr, message);
92
93       /* calculate offset to x position caused by rounding */
94       int max_chars_per_line = max_line_width / font_width;
95       int xoffset = (max_line_width - max_chars_per_line * font_width) / 2;
96
97       xpos = SX + xoffset;
98       ypos = SY + ypos_2;
99     }
100
101     Error(ERR_DEBUG, "========== %s ==========", message);
102   }
103   else
104   {
105     int max_chars_per_line = max_line_width / font_width;
106     int max_lines_per_text = 10;
107     int num_lines_spacing = (font_nr == FC_YELLOW ? 1 : 3);
108     int num_lines_printed = DrawTextBuffer(xpos, ypos, message, font_nr,
109                                            max_chars_per_line, -1,
110                                            max_lines_per_text, 0, -1,
111                                            TRUE, TRUE, FALSE);
112
113     ypos += (num_lines_printed + num_lines_spacing) * font_height;
114
115     Error(ERR_DEBUG, "%s", message);
116   }
117
118   BackToFront();
119 }
120
121 static void DrawNetworkText(char *message)
122 {
123   DrawNetworkTextExt(message, FC_YELLOW, FALSE);
124 }
125
126 static void DrawNetworkText_Success(char *message)
127 {
128   DrawNetworkTextExt(message, FC_GREEN, FALSE);
129 }
130
131 static void DrawNetworkText_Failed(char *message)
132 {
133   DrawNetworkTextExt(message, FC_RED, FALSE);
134 }
135
136 static void DrawNetworkText_Title(char *message)
137 {
138   DrawNetworkTextExt(message, FC_GREEN, TRUE);
139 }
140
141 static void SendNetworkBufferToServer(struct NetworkBuffer *nb)
142 {
143   if (!network.enabled)
144     return;
145
146   /* set message length header */
147   putNetwork32BitInteger(nb->buffer, nb->size - 4);
148
149   /* directly send the buffer to the network server */
150   SDLNet_TCP_Send(sfd, nb->buffer, nb->size);
151 }
152
153 struct NetworkClientPlayerInfo *getNetworkPlayer(int player_nr)
154 {
155   struct NetworkClientPlayerInfo *player = NULL;
156
157   for (player = &first_player; player; player = player->next)
158     if (player->nr == player_nr)
159       break;
160
161   if (player == NULL)   /* should not happen */
162     Error(ERR_EXIT, "protocol error: reference to non-existing player %d",
163           player_nr);
164
165   return player;
166 }
167
168 char *getNetworkPlayerName(int player_nr)
169 {
170   struct NetworkClientPlayerInfo *player;
171
172   if (player_nr == 0)
173     return("the network game server");
174   else if (player_nr == first_player.nr)
175     return("you");
176   else
177     for (player = &first_player; player; player = player->next)
178       if (player->nr == player_nr && strlen(player->name) > 0)
179         return(player->name);
180
181   return(EMPTY_PLAYER_NAME);
182 }
183
184 static void StartNetworkServer(int port)
185 {
186   static int p;
187
188   p = port;
189 #if defined(TARGET_SDL2)
190   server_thread = SDL_CreateThread(NetworkServerThread,
191                                    "NetworkServerThread", &p);
192 #else
193   server_thread = SDL_CreateThread(NetworkServerThread, &p);
194 #endif
195   network_server = TRUE;
196 }
197
198 boolean ConnectToServer(char *hostname, int port)
199 {
200   IPaddress ip;
201   int server_host = 0;
202   int i;
203
204   if (read_buffer == NULL)
205     read_buffer = newNetworkBuffer();
206
207   if (write_buffer == NULL)
208     write_buffer = newNetworkBuffer();
209
210   DrawNetworkText_Title("Initializing Network");
211
212   if (port == 0)
213     port = DEFAULT_SERVER_PORT;
214
215   if (hostname == NULL)
216   {
217     // if no hostname given, try to auto-detect network server in local network
218     // by doing a UDP broadcast on the network server port and wait for answer
219
220     SDLNet_SocketSet udp_socket_set = SDLNet_AllocSocketSet(1);
221     if (!udp_socket_set)
222       Error(ERR_EXIT, "SDLNet_AllocSocketSet() failed: %s"), SDLNet_GetError();
223
224     udp = SDLNet_UDP_Open(0);
225     if(!udp)
226       Error(ERR_EXIT, "SDLNet_UDP_Open() failed: %s", SDLNet_GetError());
227
228     if (SDLNet_UDP_AddSocket(udp_socket_set, udp) == -1)
229       Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_AddSocket() failed: %s"),
230         SDLNet_GetError();
231
232     char *data_ptr = "network server UDB broadcast";
233     int data_len = strlen(data_ptr) + 1;
234     IPaddress ip_address;
235
236     SDLNet_Write32(0xffffffff, &ip_address.host);       /* 255.255.255.255 */
237     SDLNet_Write16(port,       &ip_address.port);
238
239     UDPpacket packet =
240     {
241       -1,
242       (Uint8 *)data_ptr,
243       data_len,
244       data_len,
245       0,
246       ip_address
247     };
248
249     SDLNet_UDP_Send(udp, -1, &packet);
250
251     DrawNetworkText("Looking for local network server ...");
252
253     /* wait for any local network server to answer UDP broadcast */
254     for (i = 0; i < 5; i++)
255     {
256       if (SDLNet_CheckSockets(udp_socket_set, 0) == 1)
257       {
258         int num_packets = SDLNet_UDP_Recv(udp, &packet);
259
260         if (num_packets == 1)
261         {
262           DrawNetworkText_Success("Network server found!");
263
264           server_host = SDLNet_Read32(&packet.address.host);
265         }
266         else
267         {
268           DrawNetworkText_Failed("No answer from network server!");
269         }
270
271         break;
272       }
273       else
274       {
275         Delay_WithScreenUpdates(100);
276       }
277     }
278
279     if (server_host == 0)
280       DrawNetworkText_Failed("No network server found!");
281   }
282
283   rfds = SDLNet_AllocSocketSet(1);
284
285   if (hostname)
286   {
287     SDLNet_ResolveHost(&ip, hostname, port);
288
289     if (ip.host == INADDR_NONE)
290       Error(ERR_EXIT, "cannot locate host '%s'", hostname);
291     else
292       server_host = SDLNet_Read32(&ip.host);
293
294     DrawNetworkText("Connecting to remote host ...");
295   }
296   else
297   {
298     // if no hostname was given and no network server was auto-detected in the
299     // local network, try to connect to a network server at the local host
300     if (server_host == 0)
301       server_host = 0x7f000001;                 /* 127.0.0.1 */
302
303     SDLNet_Write32(server_host, &ip.host);
304     SDLNet_Write16(port,        &ip.port);
305
306     DrawNetworkText("Connecting to local host ...");
307   }
308
309   Error(ERR_DEBUG, "trying to connect to network server at %d.%d.%d.%d ...",
310         (server_host >> 24) & 0xff,
311         (server_host >> 16) & 0xff,
312         (server_host >>  8) & 0xff,
313         (server_host >>  0) & 0xff);
314
315   sfd = SDLNet_TCP_Open(&ip);
316
317   if (sfd)
318   {
319     SDLNet_TCP_AddSocket(rfds, sfd);
320
321     DrawNetworkText_Success("Successfully connected!");
322
323     return TRUE;
324   }
325   else
326   {
327     DrawNetworkText_Failed("Failed to connect to network server!");
328
329     printf("SDLNet_TCP_Open(): %s\n", SDLNet_GetError());
330   }
331
332   if (hostname)                 /* connect to specified server failed */
333     return FALSE;
334
335   DrawNetworkText("Starting new local network server ...");
336
337   StartNetworkServer(port);
338
339   /* wait for server to start up and try connecting several times */
340   for (i = 0; i < 30; i++)
341   {
342     if ((sfd = SDLNet_TCP_Open(&ip)))           /* connected */
343     {
344       DrawNetworkText_Success("Successfully connected!");
345
346       SDLNet_TCP_AddSocket(rfds, sfd);
347       return TRUE;
348     }
349
350     Delay_WithScreenUpdates(100);
351   }
352
353   DrawNetworkText_Failed("Failed to connect to network server!");
354
355   /* when reaching this point, connect to newly started server has failed */
356   return FALSE;
357 }
358
359 void SendToServer_PlayerName(char *player_name)
360 {
361   initNetworkBufferForWriting(write_buffer, OP_PLAYER_NAME, 0);
362
363   putNetworkBufferString(write_buffer, player_name);
364
365   SendNetworkBufferToServer(write_buffer);
366
367   Error(ERR_NETWORK_CLIENT, "you set your player name to \"%s\"", player_name);
368 }
369
370 void SendToServer_ProtocolVersion()
371 {
372   initNetworkBufferForWriting(write_buffer, OP_PROTOCOL_VERSION, 0);
373
374   putNetworkBuffer8BitInteger(write_buffer, PROTOCOL_VERSION_MAJOR);
375   putNetworkBuffer8BitInteger(write_buffer, PROTOCOL_VERSION_MINOR);
376   putNetworkBuffer8BitInteger(write_buffer, PROTOCOL_VERSION_PATCH);
377
378   SendNetworkBufferToServer(write_buffer);
379 }
380
381 void SendToServer_NrWanted(int nr_wanted)
382 {
383   initNetworkBufferForWriting(write_buffer, OP_NUMBER_WANTED, 0);
384
385   putNetworkBuffer8BitInteger(write_buffer, nr_wanted);
386
387   SendNetworkBufferToServer(write_buffer);
388 }
389
390 void SendToServer_LevelFile()
391 {
392   initNetworkBufferForWriting(write_buffer, OP_LEVEL_FILE, 0);
393
394   putNetworkBufferString(      write_buffer, leveldir_current->identifier);
395   putNetworkBuffer16BitInteger(write_buffer, level.file_info.nr);
396   putNetworkBuffer8BitInteger( write_buffer, level.file_info.type);
397   putNetworkBuffer8BitInteger( write_buffer, level.file_info.packed);
398   putNetworkBufferString(      write_buffer, level.file_info.basename);
399   putNetworkBufferFile(        write_buffer, level.file_info.filename);
400   putNetworkBuffer8BitInteger( write_buffer, level.use_custom_template);
401
402   if (level.use_custom_template)
403   {
404     putNetworkBufferString(write_buffer, level_template.file_info.basename);
405     putNetworkBufferFile(  write_buffer, level_template.file_info.filename);
406   }
407
408   SendNetworkBufferToServer(write_buffer);
409
410   setString(&network_level.leveldir_identifier, leveldir_current->identifier);
411
412   /* the sending client does not use network level files (but the real ones) */
413   network_level.use_network_level_files = FALSE;
414
415 #if 0
416   printf("::: '%s'\n", leveldir_current->identifier);
417   printf("::: '%d'\n", level.file_info.nr);
418   printf("::: '%d'\n", level.file_info.type);
419   printf("::: '%d'\n", level.file_info.packed);
420   printf("::: '%s'\n", level.file_info.basename);
421   printf("::: '%s'\n", level.file_info.filename);
422
423   if (level.use_custom_template)
424     printf("::: '%s'\n", level_template.file_info.filename);
425 #endif
426 }
427
428 void SendToServer_StartPlaying()
429 {
430   unsigned int new_random_seed = InitRND(level.random_seed);
431
432   initNetworkBufferForWriting(write_buffer, OP_START_PLAYING, 0);
433
434   putNetworkBufferString(      write_buffer, leveldir_current->identifier);
435   putNetworkBuffer16BitInteger(write_buffer, level_nr);
436   putNetworkBuffer32BitInteger(write_buffer, new_random_seed);
437
438   SendNetworkBufferToServer(write_buffer);
439 }
440
441 void SendToServer_PausePlaying()
442 {
443   initNetworkBufferForWriting(write_buffer, OP_PAUSE_PLAYING, 0);
444
445   SendNetworkBufferToServer(write_buffer);
446 }
447
448 void SendToServer_ContinuePlaying()
449 {
450   initNetworkBufferForWriting(write_buffer, OP_CONTINUE_PLAYING, 0);
451
452   SendNetworkBufferToServer(write_buffer);
453 }
454
455 void SendToServer_StopPlaying(int cause_for_stopping)
456 {
457   initNetworkBufferForWriting(write_buffer, OP_STOP_PLAYING, 0);
458
459   putNetworkBuffer8BitInteger(write_buffer, cause_for_stopping);
460
461   SendNetworkBufferToServer(write_buffer);
462 }
463
464 void SendToServer_MovePlayer(byte player_action)
465 {
466   initNetworkBufferForWriting(write_buffer, OP_MOVE_PLAYER, 0);
467
468   putNetworkBuffer8BitInteger(write_buffer, player_action);
469
470   SendNetworkBufferToServer(write_buffer);
471 }
472
473 static void Handle_OP_BAD_PROTOCOL_VERSION()
474 {
475   int protocol_version_major = getNetworkBuffer8BitInteger(read_buffer);
476   int protocol_version_minor = getNetworkBuffer8BitInteger(read_buffer);
477
478   Error(ERR_WARN, "protocol version mismatch");
479   Error(ERR_WARN, "server expects %d.%d.x instead of %d.%d.%d",
480         protocol_version_major,
481         protocol_version_minor,
482         PROTOCOL_VERSION_MAJOR,
483         PROTOCOL_VERSION_MINOR,
484         PROTOCOL_VERSION_PATCH);
485
486   sprintf(stop_network_client_message, "Network protocol version mismatch! Server expects version %d.%d.x instead of %d.%d.%d!",
487           protocol_version_major,
488           protocol_version_minor,
489           PROTOCOL_VERSION_MAJOR,
490           PROTOCOL_VERSION_MINOR,
491           PROTOCOL_VERSION_PATCH);
492
493   stop_network_client = TRUE;
494 }
495
496 static void Handle_OP_YOUR_NUMBER()
497 {
498   int old_client_nr = getNetworkBuffer8BitInteger(read_buffer);
499   int new_client_nr = getNetworkBuffer8BitInteger(read_buffer);
500   int new_index_nr = new_client_nr - 1;
501   struct PlayerInfo *old_local_player = local_player;
502   struct PlayerInfo *new_local_player = &stored_player[new_index_nr];
503
504   printf("OP_YOUR_NUMBER: %d\n", old_client_nr);
505   first_player.nr = new_client_nr;
506
507   if (old_local_player != new_local_player)
508   {
509     /* set relevant player settings and change to new player */
510
511     local_player = new_local_player;
512
513     old_local_player->connected_locally = FALSE;
514     new_local_player->connected_locally = TRUE;
515
516     old_local_player->connected_network = FALSE;
517     new_local_player->connected_network = TRUE;
518   }
519
520   if (first_player.nr > MAX_PLAYERS)
521     Error(ERR_EXIT, "sorry, more than %d players not allowed", MAX_PLAYERS);
522
523   Error(ERR_NETWORK_CLIENT, "you get client # %d", new_client_nr);
524
525   stored_player[new_index_nr].connected_network = TRUE;
526 }
527
528 static void Handle_OP_NUMBER_WANTED()
529 {
530   int old_client_nr    = getNetworkBuffer8BitInteger(read_buffer);
531   int client_nr_wanted = getNetworkBuffer8BitInteger(read_buffer);
532   int new_client_nr    = getNetworkBuffer8BitInteger(read_buffer);
533   int old_index_nr = old_client_nr - 1;
534   int new_index_nr = new_client_nr - 1;
535   int index_nr_wanted = client_nr_wanted - 1;
536   struct PlayerInfo *old_player = &stored_player[old_index_nr];
537   struct PlayerInfo *new_player = &stored_player[new_index_nr];
538
539   printf("OP_NUMBER_WANTED: %d\n", old_client_nr);
540
541   if (new_client_nr == client_nr_wanted)        /* switching succeeded */
542   {
543     struct NetworkClientPlayerInfo *player;
544
545     if (old_client_nr != client_nr_wanted)      /* client's nr has changed */
546       Error(ERR_NETWORK_CLIENT, "client %d switches to # %d",
547             old_client_nr, new_client_nr);
548     else if (old_client_nr == first_player.nr)  /* local player keeps his nr */
549       Error(ERR_NETWORK_CLIENT, "keeping client # %d", new_client_nr);
550
551     if (old_client_nr != new_client_nr)
552     {
553       /* set relevant player settings and change to new player */
554
555       old_player->connected_network = FALSE;
556       new_player->connected_network = TRUE;
557     }
558
559     player = getNetworkPlayer(old_client_nr);
560     player->nr = new_client_nr;
561
562     if (old_player == local_player)             /* local player switched */
563     {
564       local_player = new_player;
565
566       old_player->connected_locally = FALSE;
567       new_player->connected_locally = TRUE;
568     }
569   }
570   else if (old_client_nr == first_player.nr)    /* failed -- local player? */
571   {
572     char request[100];
573
574     sprintf(request, "Sorry! Player %d already exists! You are player %d!",
575             index_nr_wanted + 1, new_index_nr + 1);
576
577     Request(request, REQ_CONFIRM);
578
579     Error(ERR_NETWORK_CLIENT, "cannot switch -- you keep client # %d",
580           new_client_nr);
581   }
582
583   if (game_status == GAME_MODE_MAIN)
584     DrawNetworkPlayers();
585 }
586
587 static void Handle_OP_PLAYER_NAME()
588 {
589   int player_nr = getNetworkBuffer8BitInteger(read_buffer);
590   char *player_name = getNetworkBufferString(read_buffer);
591   struct NetworkClientPlayerInfo *player = getNetworkPlayer(player_nr);
592
593   printf("OP_PLAYER_NAME: %d\n", player_nr);
594
595   strncpy(player->name, player_name, MAX_PLAYER_NAME_LEN);
596   player->name[MAX_PLAYER_NAME_LEN] = '\0';
597
598   Error(ERR_NETWORK_CLIENT, "client %d calls itself \"%s\"",
599         player_nr, player->name);
600 }
601
602 static void Handle_OP_PLAYER_CONNECTED()
603 {
604   struct NetworkClientPlayerInfo *player, *last_player = NULL;
605   int new_client_nr = getNetworkBuffer8BitInteger(read_buffer);
606   int new_index_nr = new_client_nr - 1;
607
608   printf("OP_PLAYER_CONNECTED: %d\n", new_client_nr);
609   Error(ERR_NETWORK_CLIENT, "new client %d connected", new_client_nr);
610
611   for (player = &first_player; player; player = player->next)
612   {
613     if (player->nr == new_client_nr)
614       Error(ERR_EXIT, "multiplayer server sent duplicate player id");
615
616     last_player = player;
617   }
618
619   last_player->next = player =
620     checked_malloc(sizeof(struct NetworkClientPlayerInfo));
621   player->nr = new_client_nr;
622   player->name[0] = '\0';
623   player->next = NULL;
624
625   stored_player[new_index_nr].connected_network = TRUE;
626 }
627
628 static void Handle_OP_PLAYER_DISCONNECTED()
629 {
630   struct NetworkClientPlayerInfo *player, *player_disconnected;
631   int player_nr = getNetworkBuffer8BitInteger(read_buffer);
632   int index_nr = player_nr - 1;
633
634   printf("OP_PLAYER_DISCONNECTED: %d\n", player_nr);
635   player_disconnected = getNetworkPlayer(player_nr);
636   Error(ERR_NETWORK_CLIENT, "client %d (%s) disconnected",
637         player_nr, getNetworkPlayerName(player_nr));
638
639   for (player = &first_player; player; player = player->next)
640     if (player->next == player_disconnected)
641       player->next = player_disconnected->next;
642   free(player_disconnected);
643
644   stored_player[index_nr].connected_locally = FALSE;
645   stored_player[index_nr].connected_network = FALSE;
646
647   if (game_status == GAME_MODE_PLAYING)
648   {
649     char message[100];
650
651     sprintf(message, "Player %d left network server! Network game stopped!",
652             player_nr);
653
654     Request(message, REQ_CONFIRM | REQ_STAY_CLOSED);
655
656     SetGameStatus(GAME_MODE_MAIN);
657
658     DrawMainMenu();
659   }
660   else if (game_status == GAME_MODE_MAIN)
661   {
662     DrawNetworkPlayers();
663   }
664 }
665
666 static void Handle_OP_START_PLAYING()
667 {
668   int player_nr = getNetworkBuffer8BitInteger(read_buffer);
669   char *new_leveldir_identifier = getNetworkBufferString(read_buffer);
670   int new_level_nr = getNetworkBuffer16BitInteger(read_buffer);
671   unsigned int new_random_seed = getNetworkBuffer32BitInteger(read_buffer);
672
673   if (!strEqual(new_leveldir_identifier, network_level.leveldir_identifier))
674   {
675     Error(ERR_WARN, "no such level identifier: '%s'", new_leveldir_identifier);
676
677     stop_network_game = TRUE;
678
679     return;
680   }
681
682   printf("OP_START_PLAYING: %d\n", player_nr);
683   Error(ERR_NETWORK_CLIENT,
684         "client %d starts game [level %d from level identifier '%s']\n",
685         player_nr, new_level_nr, new_leveldir_identifier);
686
687   LevelDirTree *new_leveldir =
688     getTreeInfoFromIdentifier(leveldir_first, new_leveldir_identifier);
689
690   if (new_leveldir != NULL)
691   {
692     leveldir_current = new_leveldir;
693     level_nr = new_level_nr;
694   }
695
696   TapeErase();
697
698   if (network_level.use_network_level_files)
699     LoadLevelFromNetwork(&network_level.file_info,
700                          &network_level.tmpl_info);
701   else
702     LoadLevel(level_nr);
703
704   StartGameActions(FALSE, setup.autorecord, new_random_seed);
705 }
706
707 static void Handle_OP_PAUSE_PLAYING()
708 {
709   int player_nr = getNetworkBuffer8BitInteger(read_buffer);
710
711   printf("OP_PAUSE_PLAYING: %d\n", player_nr);
712   Error(ERR_NETWORK_CLIENT, "client %d pauses game", player_nr);
713
714   if (game_status == GAME_MODE_PLAYING)
715   {
716     tape.pausing = TRUE;
717     DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0);
718   }
719 }
720
721 static void Handle_OP_CONTINUE_PLAYING()
722 {
723   int player_nr = getNetworkBuffer8BitInteger(read_buffer);
724
725   printf("OP_CONTINUE_PLAYING: %d\n", player_nr);
726   Error(ERR_NETWORK_CLIENT, "client %d continues game", player_nr);
727
728   if (game_status == GAME_MODE_PLAYING)
729   {
730     tape.pausing = FALSE;
731     DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF, 0);
732   }
733 }
734
735 static void Handle_OP_STOP_PLAYING()
736 {
737   int client_nr = getNetworkBuffer8BitInteger(read_buffer);
738   int cause_for_stopping = getNetworkBuffer8BitInteger(read_buffer);
739
740   printf("OP_STOP_PLAYING: %d [%d]\n", client_nr, cause_for_stopping);
741   Error(ERR_NETWORK_CLIENT, "client %d stops game [%d]",
742         client_nr, cause_for_stopping);
743
744   if (game_status == GAME_MODE_PLAYING)
745   {
746     int index_nr = client_nr - 1;
747     struct PlayerInfo *client_player = &stored_player[index_nr];
748     boolean stopped_by_remote_player = (!client_player->connected_locally);
749     char message[100];
750
751     sprintf(message, (cause_for_stopping == NETWORK_STOP_BY_PLAYER ?
752                       "Network game stopped by player %d!" :
753                       cause_for_stopping == NETWORK_STOP_BY_ERROR ?
754                       "Network game stopped due to internal error!" :
755                       "Network game stopped!"), client_nr);
756
757     if (cause_for_stopping != NETWORK_STOP_BY_PLAYER ||
758         stopped_by_remote_player)
759       Request(message, REQ_CONFIRM | REQ_STAY_CLOSED);
760
761     SetGameStatus(GAME_MODE_MAIN);
762
763     DrawMainMenu();
764   }
765 }
766
767 static void Handle_OP_MOVE_PLAYER()
768 {
769   int player_nr = getNetworkBuffer8BitInteger(read_buffer);
770   int server_frame_counter = getNetworkBuffer32BitInteger(read_buffer);
771   int i;
772
773   if (!network_playing)
774     return;
775
776   if (server_frame_counter != FrameCounter)
777   {
778     Error(ERR_INFO, "frame counters of client %d and server out of sync",
779           player_nr);
780     Error(ERR_INFO, "frame counter of client is %d", FrameCounter);
781     Error(ERR_INFO, "frame counter of server is %d", server_frame_counter);
782     Error(ERR_INFO, "this should not happen -- please debug");
783
784     stop_network_game = TRUE;
785
786     return;
787   }
788
789   /* copy valid player actions (will be set to 0 for not connected players) */
790   for (i = 0; i < MAX_PLAYERS; i++)
791     stored_player[i].effective_action =
792       getNetworkBuffer8BitInteger(read_buffer);
793
794   network_player_action_received = TRUE;
795 }
796
797 static void Handle_OP_BROADCAST_MESSAGE()
798 {
799   int player_nr = getNetworkBuffer8BitInteger(read_buffer);
800
801   printf("OP_BROADCAST_MESSAGE: %d\n", player_nr);
802   Error(ERR_NETWORK_CLIENT, "client %d sends message", player_nr);
803 }
804
805 static void Handle_OP_LEVEL_FILE()
806 {
807   int player_nr = getNetworkBuffer8BitInteger(read_buffer);
808   char *leveldir_identifier;
809   char *network_level_dir;
810   struct LevelFileInfo *file_info = &network_level.file_info;
811   struct LevelFileInfo *tmpl_info = &network_level.tmpl_info;
812   boolean use_custom_template;
813
814   setString(&network_level.leveldir_identifier, NULL);
815   setString(&network_level.file_info.basename,  NULL);
816   setString(&network_level.file_info.filename,  NULL);
817   setString(&network_level.tmpl_info.basename,  NULL);
818   setString(&network_level.tmpl_info.filename,  NULL);
819
820   printf("OP_LEVEL_FILE: %d\n", player_nr);
821
822   leveldir_identifier = getStringCopy(getNetworkBufferString(read_buffer));
823   network_level_dir   = getNetworkLevelDir(leveldir_identifier);
824
825   file_info->nr       = getNetworkBuffer16BitInteger(read_buffer);
826   file_info->type     = getNetworkBuffer8BitInteger(read_buffer);
827   file_info->packed   = getNetworkBuffer8BitInteger(read_buffer);
828   file_info->basename = getStringCopy(getNetworkBufferString(read_buffer));
829   file_info->filename = getPath2(network_level_dir, file_info->basename);
830
831   InitNetworkLevelDirectory(leveldir_identifier);
832
833   getNetworkBufferFile(read_buffer, file_info->filename);
834
835   use_custom_template = getNetworkBuffer8BitInteger(read_buffer);
836   if (use_custom_template)
837   {
838     *tmpl_info = *file_info;
839
840     tmpl_info->basename = getStringCopy(getNetworkBufferString(read_buffer));
841     tmpl_info->filename = getPath2(network_level_dir, tmpl_info->basename);
842
843     getNetworkBufferFile(read_buffer, tmpl_info->filename);
844   }
845
846   network_level.leveldir_identifier = leveldir_identifier;
847   network_level.use_custom_template = use_custom_template;
848
849   /* the receiving client(s) use(s) the transferred network level files */
850   network_level.use_network_level_files = TRUE;
851
852 #if 0
853   printf("::: '%s'\n", leveldir_identifier);
854   printf("::: '%d'\n", file_info->nr);
855   printf("::: '%d'\n", file_info->type);
856   printf("::: '%d'\n", file_info->packed);
857   printf("::: '%s'\n", file_info->basename);
858   printf("::: '%s'\n", file_info->filename);
859
860   if (use_custom_template)
861     printf("::: '%s'\n", tmpl_info->filename);
862 #endif
863 }
864
865 static void HandleNetworkingMessage()
866 {
867   stop_network_game = FALSE;
868
869   initNetworkBufferForReading(read_buffer);
870
871   int message_type = getNetworkBuffer8BitInteger(read_buffer);
872
873   switch (message_type)
874   {
875     case OP_BAD_PROTOCOL_VERSION:
876       Handle_OP_BAD_PROTOCOL_VERSION();
877       break;
878
879     case OP_YOUR_NUMBER:
880       Handle_OP_YOUR_NUMBER();
881       break;
882
883     case OP_NUMBER_WANTED:
884       Handle_OP_NUMBER_WANTED();
885       break;
886
887     case OP_PLAYER_NAME:
888       Handle_OP_PLAYER_NAME();
889       break;
890
891     case OP_PLAYER_CONNECTED:
892       Handle_OP_PLAYER_CONNECTED();
893       break;
894
895     case OP_PLAYER_DISCONNECTED:
896       Handle_OP_PLAYER_DISCONNECTED();
897       break;
898
899     case OP_START_PLAYING:
900       Handle_OP_START_PLAYING();
901       break;
902
903     case OP_PAUSE_PLAYING:
904       Handle_OP_PAUSE_PLAYING();
905       break;
906
907     case OP_CONTINUE_PLAYING:
908       Handle_OP_CONTINUE_PLAYING();
909       break;
910
911     case OP_STOP_PLAYING:
912       Handle_OP_STOP_PLAYING();
913       break;
914
915     case OP_MOVE_PLAYER:
916       Handle_OP_MOVE_PLAYER();
917       break;
918
919     case OP_BROADCAST_MESSAGE:
920       Handle_OP_BROADCAST_MESSAGE();
921       break;
922
923     case OP_LEVEL_FILE:
924       Handle_OP_LEVEL_FILE();
925       break;
926
927     default:
928       if (options.verbose)
929         Error(ERR_NETWORK_CLIENT,
930               "unknown opcode %d from server", message_type);
931   }
932
933   fflush(stdout);
934
935   /* in case of internal error, stop network game */
936   if (stop_network_game)
937     SendToServer_StopPlaying(NETWORK_STOP_BY_ERROR);
938 }
939
940 static char *HandleNetworkingPackets()
941 {
942   while (1)
943   {
944     /* ---------- check network server for activity ---------- */
945
946     int num_active_sockets = SDLNet_CheckSockets(rfds, 0);
947
948     if (num_active_sockets < 0)
949       return "Error checking network sockets!";
950
951     if (num_active_sockets == 0)
952       break;    // no active sockets, stop here
953
954     /* ---------- read packets from network server ---------- */
955
956     initNetworkBufferForReceiving(read_buffer);
957
958     int num_bytes = receiveNetworkBufferPacket(read_buffer, sfd);
959
960     if (num_bytes < 0)
961       return "Error reading from network server!";
962
963     if (num_bytes == 0)
964       return "Connection to network server lost!";
965
966     HandleNetworkingMessage();
967
968     if (stop_network_client)
969       return stop_network_client_message;
970   }
971
972   return NULL;
973 }
974
975 static void FreeNetworkClientPlayerInfo(struct NetworkClientPlayerInfo *player)
976 {
977   if (player == NULL)
978     return;
979
980   if (player->next)
981     FreeNetworkClientPlayerInfo(player->next);
982
983   checked_free(player);
984 }
985
986 static void HandleNetworkingDisconnect()
987 {
988   int i;
989
990   SDLNet_TCP_DelSocket(rfds, sfd);
991   SDLNet_TCP_Close(sfd);
992
993   network_playing = FALSE;
994
995   network.enabled = FALSE;
996   network.connected = FALSE;
997
998   setup.network_mode = FALSE;
999
1000   for (i = 0; i < MAX_PLAYERS; i++)
1001     stored_player[i].connected_network = FALSE;
1002
1003   FreeNetworkClientPlayerInfo(first_player.next);
1004
1005   first_player.nr = 0;
1006   first_player.next = NULL;
1007 }
1008
1009 void HandleNetworking()
1010 {
1011   char *error_message = HandleNetworkingPackets();
1012
1013   if (error_message != NULL)
1014   {
1015     HandleNetworkingDisconnect();
1016
1017     if (game_status == GAME_MODE_PLAYING)
1018     {
1019       Request(error_message, REQ_CONFIRM | REQ_STAY_CLOSED);
1020
1021       SetGameStatus(GAME_MODE_MAIN);
1022
1023       DrawMainMenu();
1024     }
1025     else
1026     {
1027       Request(error_message, REQ_CONFIRM);
1028
1029       if (game_status == GAME_MODE_MAIN)
1030         ClearNetworkPlayers();
1031     }
1032   }
1033 }
1034
1035 void DisconnectFromNetworkServer()
1036 {
1037   DrawNetworkText_Title("Terminating Network");
1038   DrawNetworkText("Disconnecting from network server ...");
1039
1040   HandleNetworkingDisconnect();
1041
1042   DrawNetworkText_Success("Successfully disconnected!");
1043
1044   /* short time to recognize result of network initialization */
1045   Delay_WithScreenUpdates(1000);
1046 }