1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
15 #include "libgame/libgame.h"
27 struct NetworkClientPlayerInfo
30 char name[MAX_PLAYER_NAME_LEN + 1];
31 struct NetworkClientPlayerInfo *next;
34 static struct NetworkClientPlayerInfo first_player =
43 static TCPsocket sfd; // TCP server socket
44 static UDPsocket udp; // UDP server socket
45 static SDLNet_SocketSet rfds; // socket set
47 static struct NetworkBuffer *read_buffer = NULL;
48 static struct NetworkBuffer *write_buffer = NULL;
50 static boolean stop_network_game = FALSE;
51 static boolean stop_network_client = FALSE;
52 static char stop_network_client_message[MAX_OUTPUT_LINESIZE + 1];
54 static struct NetworkLevelInfo network_level;
56 static void DrawNetworkTextExt(char *message, int font_nr, boolean initialize)
58 static int xpos = 0, ypos = 0;
59 static int max_line_width = 0;
60 int font_width = getFontWidth(font_nr);
61 int font_height = getFontHeight(font_nr);
67 if (game_status == GAME_MODE_LOADING)
69 max_line_width = WIN_XSIZE;
71 xpos = (max_line_width - getTextWidth(message, font_nr)) / 2;
74 DrawText(xpos, ypos, message, font_nr);
81 max_line_width = SXSIZE;
83 DrawTextSCentered(ypos_1, font_nr, message);
85 // calculate offset to x position caused by rounding
86 int max_chars_per_line = max_line_width / font_width;
87 int xoffset = (max_line_width - max_chars_per_line * font_width) / 2;
93 Debug("network:client", "========== %s ==========", message);
97 int max_chars_per_line = max_line_width / font_width;
98 int max_lines_per_text = 10;
99 int num_lines_spacing = (font_nr == FC_YELLOW ? 1 : 3);
100 int num_lines_printed = DrawTextBuffer(xpos, ypos, message, font_nr,
101 max_chars_per_line, -1,
102 max_lines_per_text, 0, -1,
105 ypos += (num_lines_printed + num_lines_spacing) * font_height;
107 Debug("network:client", "%s", message);
113 static void DrawNetworkText(char *message)
115 DrawNetworkTextExt(message, FC_YELLOW, FALSE);
118 static void DrawNetworkText_Success(char *message)
120 DrawNetworkTextExt(message, FC_GREEN, FALSE);
123 static void DrawNetworkText_Failed(char *message)
125 DrawNetworkTextExt(message, FC_RED, FALSE);
128 static void DrawNetworkText_Title(char *message)
130 DrawNetworkTextExt(message, FC_GREEN, TRUE);
133 static void SendNetworkBufferToServer(struct NetworkBuffer *nb)
135 if (!network.enabled)
138 // set message length header
139 putNetwork32BitInteger(nb->buffer, nb->size - 4);
141 // directly send the buffer to the network server
142 SDLNet_TCP_Send(sfd, nb->buffer, nb->size);
145 static struct NetworkClientPlayerInfo *getNetworkPlayer(int player_nr)
147 struct NetworkClientPlayerInfo *player = NULL;
149 for (player = &first_player; player; player = player->next)
150 if (player->nr == player_nr)
153 if (player == NULL) // should not happen
154 Fail("protocol error: reference to non-existing player %d", player_nr);
159 char *getNetworkPlayerName(int player_nr)
161 struct NetworkClientPlayerInfo *player;
164 return "the network game server";
165 else if (player_nr == first_player.nr)
168 for (player = &first_player; player; player = player->next)
169 if (player->nr == player_nr && strlen(player->name) > 0)
172 return EMPTY_PLAYER_NAME;
175 boolean hasStartedNetworkGame(void)
177 return !network_level.use_network_level_files;
180 static boolean hasPathSeparator(char *s)
182 return (strchr(s, '/') != NULL);
185 static void StartNetworkServer(int port)
191 network.server_thread = SDL_CreateThread(NetworkServerThread,
192 "NetworkServerThread", &p);
195 boolean ConnectToServer(char *hostname, int port)
201 if (read_buffer == NULL)
202 read_buffer = newNetworkBuffer();
204 if (write_buffer == NULL)
205 write_buffer = newNetworkBuffer();
207 DrawNetworkText_Title("Initializing Network");
210 port = DEFAULT_SERVER_PORT;
212 if (hostname == NULL)
214 // if no hostname given, try to auto-detect network server in local network
215 // by doing a UDP broadcast on the network server port and wait for answer
217 SDLNet_SocketSet udp_socket_set = SDLNet_AllocSocketSet(1);
219 Fail("SDLNet_AllocSocketSet() failed: %s"), SDLNet_GetError();
221 udp = SDLNet_UDP_Open(0);
223 Fail("SDLNet_UDP_Open() failed: %s", SDLNet_GetError());
225 if (SDLNet_UDP_AddSocket(udp_socket_set, udp) == -1)
226 Fail("SDLNet_TCP_AddSocket() failed: %s"), SDLNet_GetError();
228 char *data_ptr = "network server UDB broadcast";
229 int data_len = strlen(data_ptr) + 1;
230 IPaddress ip_address;
232 SDLNet_Write32(0xffffffff, &ip_address.host); // 255.255.255.255
233 SDLNet_Write16(port, &ip_address.port);
245 SDLNet_UDP_Send(udp, -1, &packet);
247 DrawNetworkText("Looking for nearby network server ...");
249 // wait for any nearby network server to answer UDP broadcast
250 for (i = 0; i < 5; i++)
252 if (SDLNet_CheckSockets(udp_socket_set, 0) == 1)
254 int num_packets = SDLNet_UDP_Recv(udp, &packet);
256 if (num_packets == 1)
260 server_host = SDLNet_Read32(&packet.address.host);
262 sprintf(message, "Network server found at %d.%d.%d.%d!",
263 (server_host >> 24) & 0xff,
264 (server_host >> 16) & 0xff,
265 (server_host >> 8) & 0xff,
266 (server_host >> 0) & 0xff);
268 DrawNetworkText_Success(message);
272 DrawNetworkText_Failed("No answer from network server!");
279 Delay_WithScreenUpdates(100);
283 if (server_host == 0)
284 DrawNetworkText_Failed("No nearby network server found!");
287 rfds = SDLNet_AllocSocketSet(1);
293 SDLNet_ResolveHost(&ip, hostname, port);
295 if (ip.host == INADDR_NONE)
297 sprintf(message, "Failed to resolve network server hostname '%s'!",
300 DrawNetworkText_Failed(message);
306 server_host = SDLNet_Read32(&ip.host);
309 sprintf(message, "Connecting to network server host %s ...", hostname);
311 DrawNetworkText(message);
315 // if no hostname was given and no network server was auto-detected in the
316 // local network, try to connect to a network server at the local host
317 if (server_host == 0)
319 server_host = 0x7f000001; // 127.0.0.1
321 DrawNetworkText("Looking for local network server ...");
325 DrawNetworkText("Connecting to network server ...");
328 SDLNet_Write32(server_host, &ip.host);
329 SDLNet_Write16(port, &ip.port);
332 Debug("network:client", "trying to connect to network server at %d.%d.%d.%d ...",
333 (server_host >> 24) & 0xff,
334 (server_host >> 16) & 0xff,
335 (server_host >> 8) & 0xff,
336 (server_host >> 0) & 0xff);
338 sfd = SDLNet_TCP_Open(&ip);
342 SDLNet_TCP_AddSocket(rfds, sfd);
344 DrawNetworkText_Success("Successfully connected!");
351 DrawNetworkText_Failed("Failed to connect to network server!");
353 DrawNetworkText_Failed("No local network server found!");
355 Debug("network:client", "SDLNet_TCP_Open(): %s", SDLNet_GetError());
358 if (hostname) // connect to specified server failed
361 DrawNetworkText("Starting new local network server ...");
363 StartNetworkServer(port);
365 // wait for server to start up and try connecting several times
366 for (i = 0; i < 30; i++)
368 if ((sfd = SDLNet_TCP_Open(&ip))) // connected
370 DrawNetworkText_Success("Successfully connected to newly started network server!");
372 SDLNet_TCP_AddSocket(rfds, sfd);
377 Delay_WithScreenUpdates(100);
380 DrawNetworkText_Failed("Failed to connect to newly started network server!");
382 // when reaching this point, connect to newly started server has failed
386 void SendToServer_PlayerName(char *player_name)
388 initNetworkBufferForWriting(write_buffer, OP_PLAYER_NAME, 0);
390 putNetworkBufferString(write_buffer, player_name);
392 SendNetworkBufferToServer(write_buffer);
394 Debug("network:client", "you set your player name to \"%s\"", player_name);
397 void SendToServer_ProtocolVersion(void)
399 initNetworkBufferForWriting(write_buffer, OP_PROTOCOL_VERSION, 0);
401 putNetworkBuffer8BitInteger(write_buffer, PROTOCOL_VERSION_MAJOR);
402 putNetworkBuffer8BitInteger(write_buffer, PROTOCOL_VERSION_MINOR);
403 putNetworkBuffer8BitInteger(write_buffer, PROTOCOL_VERSION_PATCH);
405 SendNetworkBufferToServer(write_buffer);
408 void SendToServer_NrWanted(int nr_wanted)
410 initNetworkBufferForWriting(write_buffer, OP_NUMBER_WANTED, 0);
412 putNetworkBuffer8BitInteger(write_buffer, nr_wanted);
414 SendNetworkBufferToServer(write_buffer);
417 void SendToServer_LevelFile(void)
419 initNetworkBufferForWriting(write_buffer, OP_LEVEL_FILE, 0);
421 putNetworkBufferString( write_buffer, leveldir_current->identifier);
422 putNetworkBuffer16BitInteger(write_buffer, level.file_info.nr);
423 putNetworkBuffer8BitInteger( write_buffer, level.file_info.type);
424 putNetworkBuffer8BitInteger( write_buffer, level.file_info.packed);
425 putNetworkBufferString( write_buffer, level.file_info.basename);
426 putNetworkBufferFile( write_buffer, level.file_info.filename);
427 putNetworkBuffer8BitInteger( write_buffer, level.use_custom_template);
429 if (level.use_custom_template)
431 putNetworkBufferString(write_buffer, level_template.file_info.basename);
432 putNetworkBufferFile( write_buffer, level_template.file_info.filename);
435 SendNetworkBufferToServer(write_buffer);
437 setString(&network_level.leveldir_identifier, leveldir_current->identifier);
439 // the sending client does not use network level files (but the real ones)
440 network_level.use_network_level_files = FALSE;
443 Debug("network:client", "'%s'", leveldir_current->identifier);
444 Debug("network:client", "'%d'", level.file_info.nr);
445 Debug("network:client", "'%d'", level.file_info.type);
446 Debug("network:client", "'%d'", level.file_info.packed);
447 Debug("network:client", "'%s'", level.file_info.basename);
448 Debug("network:client", "'%s'", level.file_info.filename);
450 if (level.use_custom_template)
451 Debug("network:client", "'%s'", level_template.file_info.filename);
455 void SendToServer_StartPlaying(void)
457 unsigned int new_random_seed = InitRND(level.random_seed);
459 initNetworkBufferForWriting(write_buffer, OP_START_PLAYING, 0);
461 putNetworkBufferString( write_buffer, leveldir_current->identifier);
462 putNetworkBuffer16BitInteger(write_buffer, level_nr);
463 putNetworkBuffer32BitInteger(write_buffer, new_random_seed);
465 SendNetworkBufferToServer(write_buffer);
468 void SendToServer_PausePlaying(void)
470 initNetworkBufferForWriting(write_buffer, OP_PAUSE_PLAYING, 0);
472 SendNetworkBufferToServer(write_buffer);
475 void SendToServer_ContinuePlaying(void)
477 initNetworkBufferForWriting(write_buffer, OP_CONTINUE_PLAYING, 0);
479 SendNetworkBufferToServer(write_buffer);
482 void SendToServer_StopPlaying(int cause_for_stopping)
484 initNetworkBufferForWriting(write_buffer, OP_STOP_PLAYING, 0);
486 putNetworkBuffer8BitInteger(write_buffer, cause_for_stopping);
488 SendNetworkBufferToServer(write_buffer);
491 void SendToServer_MovePlayer(byte player_action)
493 initNetworkBufferForWriting(write_buffer, OP_MOVE_PLAYER, 0);
495 putNetworkBuffer8BitInteger(write_buffer, player_action);
497 SendNetworkBufferToServer(write_buffer);
500 static void Handle_OP_BAD_PROTOCOL_VERSION(void)
502 int protocol_version_major = getNetworkBuffer8BitInteger(read_buffer);
503 int protocol_version_minor = getNetworkBuffer8BitInteger(read_buffer);
505 Warn("protocol version mismatch");
506 Warn("server expects %d.%d.x instead of %d.%d.%d",
507 protocol_version_major,
508 protocol_version_minor,
509 PROTOCOL_VERSION_MAJOR,
510 PROTOCOL_VERSION_MINOR,
511 PROTOCOL_VERSION_PATCH);
513 sprintf(stop_network_client_message, "Network protocol version mismatch! Server expects version %d.%d.x instead of %d.%d.%d!",
514 protocol_version_major,
515 protocol_version_minor,
516 PROTOCOL_VERSION_MAJOR,
517 PROTOCOL_VERSION_MINOR,
518 PROTOCOL_VERSION_PATCH);
520 stop_network_client = TRUE;
523 static void Handle_OP_YOUR_NUMBER(void)
525 int old_client_nr = getNetworkBuffer8BitInteger(read_buffer);
526 int new_client_nr = getNetworkBuffer8BitInteger(read_buffer);
527 int new_index_nr = new_client_nr - 1;
528 struct PlayerInfo *old_local_player = local_player;
529 struct PlayerInfo *new_local_player = &stored_player[new_index_nr];
531 Debug("network:client", "OP_YOUR_NUMBER: %d", old_client_nr);
533 first_player.nr = new_client_nr;
535 if (old_local_player != new_local_player)
537 // set relevant player settings and change to new player
539 local_player = new_local_player;
541 old_local_player->connected_locally = FALSE;
542 new_local_player->connected_locally = TRUE;
544 old_local_player->connected_network = FALSE;
545 new_local_player->connected_network = TRUE;
548 if (first_player.nr > MAX_PLAYERS)
549 Fail("sorry, more than %d players not allowed", MAX_PLAYERS);
551 Debug("network:client", "you get client # %d", new_client_nr);
553 stored_player[new_index_nr].connected_network = TRUE;
556 static void Handle_OP_NUMBER_WANTED(void)
558 int old_client_nr = getNetworkBuffer8BitInteger(read_buffer);
559 int client_nr_wanted = getNetworkBuffer8BitInteger(read_buffer);
560 int new_client_nr = getNetworkBuffer8BitInteger(read_buffer);
561 int old_index_nr = old_client_nr - 1;
562 int new_index_nr = new_client_nr - 1;
563 int index_nr_wanted = client_nr_wanted - 1;
564 struct PlayerInfo *old_player = &stored_player[old_index_nr];
565 struct PlayerInfo *new_player = &stored_player[new_index_nr];
567 Debug("network:client", "OP_NUMBER_WANTED: %d", old_client_nr);
569 if (new_client_nr == client_nr_wanted) // switching succeeded
571 struct NetworkClientPlayerInfo *player;
573 if (old_client_nr != client_nr_wanted) // client's nr has changed
574 Debug("network:client", "client %d switches to # %d",
575 old_client_nr, new_client_nr);
576 else if (old_client_nr == first_player.nr) // local player keeps his nr
577 Debug("network:client", "keeping client # %d", new_client_nr);
579 if (old_client_nr != new_client_nr)
581 // set relevant player settings and change to new player
583 old_player->connected_network = FALSE;
584 new_player->connected_network = TRUE;
587 player = getNetworkPlayer(old_client_nr);
588 player->nr = new_client_nr;
590 if (old_player == local_player) // local player switched
592 local_player = new_player;
594 old_player->connected_locally = FALSE;
595 new_player->connected_locally = TRUE;
598 else if (old_client_nr == first_player.nr) // failed -- local player?
602 sprintf(request, "Sorry! Player %d already exists! You are player %d!",
603 index_nr_wanted + 1, new_index_nr + 1);
605 Request(request, REQ_CONFIRM);
607 Debug("network:client", "cannot switch -- you keep client # %d",
611 if (game_status == GAME_MODE_MAIN)
612 DrawNetworkPlayers();
615 static void Handle_OP_PLAYER_NAME(void)
617 int player_nr = getNetworkBuffer8BitInteger(read_buffer);
618 char *player_name = getNetworkBufferString(read_buffer);
619 struct NetworkClientPlayerInfo *player = getNetworkPlayer(player_nr);
621 Debug("network:client", "OP_PLAYER_NAME: %d", player_nr);
623 strncpy(player->name, player_name, MAX_PLAYER_NAME_LEN);
624 player->name[MAX_PLAYER_NAME_LEN] = '\0';
626 Debug("network:client", "client %d calls itself \"%s\"",
627 player_nr, player->name);
630 static void Handle_OP_PLAYER_CONNECTED(void)
632 struct NetworkClientPlayerInfo *player, *last_player = NULL;
633 int new_client_nr = getNetworkBuffer8BitInteger(read_buffer);
634 int new_index_nr = new_client_nr - 1;
636 Debug("network:client", "OP_PLAYER_CONNECTED: %d", new_client_nr);
637 Debug("network:client", "new client %d connected", new_client_nr);
639 for (player = &first_player; player; player = player->next)
641 if (player->nr == new_client_nr)
642 Fail("multiplayer server sent duplicate player id");
644 last_player = player;
647 last_player->next = player =
648 checked_malloc(sizeof(struct NetworkClientPlayerInfo));
649 player->nr = new_client_nr;
650 player->name[0] = '\0';
653 stored_player[new_index_nr].connected_network = TRUE;
656 static void Handle_OP_PLAYER_DISCONNECTED(void)
658 struct NetworkClientPlayerInfo *player, *player_disconnected;
659 int player_nr = getNetworkBuffer8BitInteger(read_buffer);
660 int index_nr = player_nr - 1;
662 Debug("network:client", "OP_PLAYER_DISCONNECTED: %d", player_nr);
663 Debug("network:client", "client %d (%s) disconnected",
664 player_nr, getNetworkPlayerName(player_nr));
666 player_disconnected = getNetworkPlayer(player_nr);
668 for (player = &first_player; player; player = player->next)
669 if (player->next == player_disconnected)
670 player->next = player_disconnected->next;
671 free(player_disconnected);
673 stored_player[index_nr].connected_locally = FALSE;
674 stored_player[index_nr].connected_network = FALSE;
676 if (game_status == GAME_MODE_PLAYING)
680 sprintf(message, "Player %d left network server! Network game stopped!",
683 Request(message, REQ_CONFIRM | REQ_STAY_CLOSED);
685 SetGameStatus(GAME_MODE_MAIN);
689 else if (game_status == GAME_MODE_MAIN)
691 DrawNetworkPlayers();
695 static void Handle_OP_START_PLAYING(void)
697 int player_nr = getNetworkBuffer8BitInteger(read_buffer);
698 char *new_leveldir_identifier = getNetworkBufferString(read_buffer);
699 int new_level_nr = getNetworkBuffer16BitInteger(read_buffer);
700 unsigned int new_random_seed = getNetworkBuffer32BitInteger(read_buffer);
702 if (!strEqual(new_leveldir_identifier, network_level.leveldir_identifier))
704 Warn("no such level identifier: '%s'", new_leveldir_identifier);
706 stop_network_game = TRUE;
711 Debug("network:client", "OP_START_PLAYING: %d", player_nr);
712 Debug("network:client",
713 "client %d starts game [level %d from level identifier '%s']",
714 player_nr, new_level_nr, new_leveldir_identifier);
716 LevelDirTree *new_leveldir =
717 getTreeInfoFromIdentifier(leveldir_first, new_leveldir_identifier);
719 if (new_leveldir != NULL)
721 leveldir_current = new_leveldir;
722 level_nr = new_level_nr;
725 // needed if level set of network game changed graphics, sounds or music
726 ReloadCustomArtwork(0);
730 if (network_level.use_network_level_files)
731 LoadNetworkLevel(&network_level);
735 StartGameActions(FALSE, setup.autorecord, new_random_seed);
738 static void Handle_OP_PAUSE_PLAYING(void)
740 int player_nr = getNetworkBuffer8BitInteger(read_buffer);
742 Debug("network:client", "OP_PAUSE_PLAYING: %d", player_nr);
743 Debug("network:client", "client %d pauses game", player_nr);
745 if (game_status == GAME_MODE_PLAYING)
748 DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0);
752 static void Handle_OP_CONTINUE_PLAYING(void)
754 int player_nr = getNetworkBuffer8BitInteger(read_buffer);
756 Debug("network:client", "OP_CONTINUE_PLAYING: %d", player_nr);
757 Debug("network:client", "client %d continues game", player_nr);
759 if (game_status == GAME_MODE_PLAYING)
761 tape.pausing = FALSE;
762 DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF, 0);
766 static void Handle_OP_STOP_PLAYING(void)
768 int client_nr = getNetworkBuffer8BitInteger(read_buffer);
769 int cause_for_stopping = getNetworkBuffer8BitInteger(read_buffer);
771 Debug("network:client", "OP_STOP_PLAYING: %d [%d]",
772 client_nr, cause_for_stopping);
773 Debug("network:client", "client %d stops game [%d]",
774 client_nr, cause_for_stopping);
776 if (game_status == GAME_MODE_PLAYING)
778 int index_nr = client_nr - 1;
779 struct PlayerInfo *client_player = &stored_player[index_nr];
780 boolean stopped_by_remote_player = (!client_player->connected_locally);
783 if (cause_for_stopping == NETWORK_STOP_BY_PLAYER)
784 sprintf(message, "Network game stopped by player %d!", client_nr);
786 sprintf(message, (cause_for_stopping == NETWORK_STOP_BY_ERROR ?
787 "Network game stopped due to internal error!" :
788 "Network game stopped!"));
790 if (cause_for_stopping != NETWORK_STOP_BY_PLAYER ||
791 stopped_by_remote_player)
792 Request(message, REQ_CONFIRM | REQ_STAY_CLOSED);
794 SetGameStatus(GAME_MODE_MAIN);
800 static void Handle_OP_MOVE_PLAYER(void)
802 int player_nr = getNetworkBuffer8BitInteger(read_buffer);
803 int server_frame_counter = getNetworkBuffer32BitInteger(read_buffer);
806 if (!network_playing)
809 if (server_frame_counter != FrameCounter)
811 Warn("frame counters of client %d and server out of sync", player_nr);
812 Warn("frame counter of client is %d", FrameCounter);
813 Warn("frame counter of server is %d", server_frame_counter);
814 Warn("this should not happen -- please debug");
816 stop_network_game = TRUE;
821 // copy valid player actions (will be set to 0 for not connected players)
822 for (i = 0; i < MAX_PLAYERS; i++)
823 stored_player[i].effective_action =
824 getNetworkBuffer8BitInteger(read_buffer);
826 network_player_action_received = TRUE;
829 static void Handle_OP_BROADCAST_MESSAGE(void)
831 int player_nr = getNetworkBuffer8BitInteger(read_buffer);
833 Debug("network:client", "OP_BROADCAST_MESSAGE: %d", player_nr);
834 Debug("network:client", "client %d sends message", player_nr);
837 static void Handle_OP_LEVEL_FILE(void)
839 int player_nr = getNetworkBuffer8BitInteger(read_buffer);
840 char *leveldir_identifier;
841 char *network_level_dir;
842 struct LevelFileInfo *file_info = &network_level.file_info;
843 struct LevelFileInfo *tmpl_info = &network_level.tmpl_info;
844 boolean use_custom_template;
846 setString(&network_level.leveldir_identifier, NULL);
847 setString(&network_level.file_info.basename, NULL);
848 setString(&network_level.file_info.filename, NULL);
849 setString(&network_level.tmpl_info.basename, NULL);
850 setString(&network_level.tmpl_info.filename, NULL);
852 Debug("network:client", "OP_LEVEL_FILE: %d", player_nr);
854 leveldir_identifier = getStringCopy(getNetworkBufferString(read_buffer));
856 if (hasPathSeparator(leveldir_identifier))
857 Fail("protocol error: invalid filename from network client");
859 InitNetworkLevelDirectory(leveldir_identifier);
861 network_level_dir = getNetworkLevelDir(leveldir_identifier);
863 file_info->nr = getNetworkBuffer16BitInteger(read_buffer);
864 file_info->type = getNetworkBuffer8BitInteger(read_buffer);
865 file_info->packed = getNetworkBuffer8BitInteger(read_buffer);
866 file_info->basename = getStringCopy(getNetworkBufferString(read_buffer));
867 file_info->filename = getPath2(network_level_dir, file_info->basename);
869 if (hasPathSeparator(file_info->basename))
870 Fail("protocol error: invalid filename from network client");
872 int num_bytes = getNetworkBufferFile(read_buffer, file_info->filename);
874 // if received level file is empty, remove it (as being non-existent)
876 remove(file_info->filename);
878 use_custom_template = getNetworkBuffer8BitInteger(read_buffer);
879 if (use_custom_template)
881 *tmpl_info = *file_info;
883 tmpl_info->basename = getStringCopy(getNetworkBufferString(read_buffer));
884 tmpl_info->filename = getPath2(network_level_dir, tmpl_info->basename);
886 if (hasPathSeparator(tmpl_info->basename))
887 Fail("protocol error: invalid filename from network client");
889 getNetworkBufferFile(read_buffer, tmpl_info->filename);
891 // if received level file is empty, use level template file instead
893 setString(&file_info->filename, tmpl_info->filename);
896 network_level.leveldir_identifier = leveldir_identifier;
897 network_level.use_custom_template = use_custom_template;
899 // the receiving client(s) use(s) the transferred network level files
900 network_level.use_network_level_files = TRUE;
903 Debug("network:client", "'%s'", leveldir_identifier);
904 Debug("network:client", "'%d'", file_info->nr);
905 Debug("network:client", "'%d'", file_info->type);
906 Debug("network:client", "'%d'", file_info->packed);
907 Debug("network:client", "'%s'", file_info->basename);
908 Debug("network:client", "'%s'", file_info->filename);
910 if (use_custom_template)
911 Debug("network:client", "'%s'", tmpl_info->filename);
915 static void HandleNetworkingMessage(void)
917 stop_network_game = FALSE;
919 initNetworkBufferForReading(read_buffer);
921 int message_type = getNetworkBuffer8BitInteger(read_buffer);
923 switch (message_type)
925 case OP_BAD_PROTOCOL_VERSION:
926 Handle_OP_BAD_PROTOCOL_VERSION();
930 Handle_OP_YOUR_NUMBER();
933 case OP_NUMBER_WANTED:
934 Handle_OP_NUMBER_WANTED();
938 Handle_OP_PLAYER_NAME();
941 case OP_PLAYER_CONNECTED:
942 Handle_OP_PLAYER_CONNECTED();
945 case OP_PLAYER_DISCONNECTED:
946 Handle_OP_PLAYER_DISCONNECTED();
949 case OP_START_PLAYING:
950 Handle_OP_START_PLAYING();
953 case OP_PAUSE_PLAYING:
954 Handle_OP_PAUSE_PLAYING();
957 case OP_CONTINUE_PLAYING:
958 Handle_OP_CONTINUE_PLAYING();
961 case OP_STOP_PLAYING:
962 Handle_OP_STOP_PLAYING();
966 Handle_OP_MOVE_PLAYER();
969 case OP_BROADCAST_MESSAGE:
970 Handle_OP_BROADCAST_MESSAGE();
974 Handle_OP_LEVEL_FILE();
978 Debug("network:client", "unknown opcode %d from server", message_type);
983 // in case of internal error, stop network game
984 if (stop_network_game)
985 SendToServer_StopPlaying(NETWORK_STOP_BY_ERROR);
988 static char *HandleNetworkingPackets(void)
992 // ---------- check network server for activity ----------
994 int num_active_sockets = SDLNet_CheckSockets(rfds, 0);
996 if (num_active_sockets < 0)
997 return "Error checking network sockets!";
999 if (num_active_sockets == 0)
1000 break; // no active sockets, stop here
1002 // ---------- read packets from network server ----------
1004 initNetworkBufferForReceiving(read_buffer);
1006 int num_bytes = receiveNetworkBufferPacket(read_buffer, sfd);
1009 return "Error reading from network server!";
1012 return "Connection to network server lost!";
1014 HandleNetworkingMessage();
1016 if (stop_network_client)
1017 return stop_network_client_message;
1023 static void FreeNetworkClientPlayerInfo(struct NetworkClientPlayerInfo *player)
1029 FreeNetworkClientPlayerInfo(player->next);
1031 checked_free(player);
1034 static void HandleNetworkingDisconnect(void)
1038 SDLNet_TCP_DelSocket(rfds, sfd);
1039 SDLNet_TCP_Close(sfd);
1041 network_playing = FALSE;
1043 network.enabled = FALSE;
1044 network.connected = FALSE;
1046 setup.network_mode = FALSE;
1048 for (i = 0; i < MAX_PLAYERS; i++)
1049 stored_player[i].connected_network = FALSE;
1051 FreeNetworkClientPlayerInfo(first_player.next);
1053 first_player.nr = 0;
1054 first_player.next = NULL;
1057 void HandleNetworking(void)
1059 // do not handle any networking packets if request dialog is active
1060 if (game.request_active)
1063 char *error_message = HandleNetworkingPackets();
1065 if (error_message != NULL)
1067 HandleNetworkingDisconnect();
1069 if (game_status == GAME_MODE_PLAYING)
1071 Request(error_message, REQ_CONFIRM | REQ_STAY_CLOSED);
1073 SetGameStatus(GAME_MODE_MAIN);
1079 Request(error_message, REQ_CONFIRM);
1081 if (game_status == GAME_MODE_MAIN)
1082 ClearNetworkPlayers();
1087 void DisconnectFromNetworkServer(void)
1089 DrawNetworkText_Title("Terminating Network");
1090 DrawNetworkText("Disconnecting from network server ...");
1092 HandleNetworkingDisconnect();
1094 DrawNetworkText_Success("Successfully disconnected!");