/* GameServer: this file will hold the protocol for the gameserver communication */ #include "bomberclone.h" #include "network.h" #include "gamesrv.h" static int sock = -1; struct game_entry gse[MAX_GAMESRVENTRYS]; _menu menu[22]; int menuselect = 0; /* We want to get a server */ void gamesrv_getserver () { int i, keypressed = 1, done = 0, ds = 0, gserv = bman.notifygamemaster, bx, by; SDL_Event event; Uint8 *keys; menuselect = 0; for (i = 0; i < MAX_GAMESRVENTRYS; i++) { gse[i].name[0] = 0; gse[i].host[0] = 0; gse[i].port[0] = 0; } for (i = 0; i < 21; i++) { menu[i].index = 0; menu[i].text[0] = 0; } if (!gserv) { menu[0].index = 1; sprintf (menu[0].text, "Scan for Games on the MasterServer"); } sprintf (menu[10].text, "User defined Server List"); menu[20].index = 1; sprintf (menu[20].text, "Enter an IP-Address"); menu[21].index = -1; for (i = 1; i <= MAX_SERVERENTRYS; i++) { menu[i + 10].index = 1; sprintf (menu[i + 10].text, "%d) %s", i, bman.serverlist[i - 1].name); } draw_logo (); draw_menu ("Select Server", menu, &bx, &by); if (gserv) { if (gamesrv_startudp () == -1) return; gamesrv_browse (1); } draw_select (menuselect, menu, bx, by); SDL_Flip (gfx.screen); while (menuselect != -1 && done == 0) { if (gserv) i = gamesrv_getglist (); /*keyboard */ if (SDL_PollEvent (&event) != 0) switch (event.type) { case (SDL_QUIT): bman.state = GS_quit; menuselect = -1; done = 1; } keys = SDL_GetKeyState (NULL); if (keys[SDLK_ESCAPE] && event.type == SDL_KEYDOWN) { /* we want to quit */ done = 1; keypressed = 1; menuselect = -1; } if (keys[SDLK_DOWN] && (!keypressed)) { menuselect++; while (menu[menuselect].index == 0) menuselect++; if (menu[menuselect].index == -1) { menuselect = 0; while (menu[menuselect].index == 0) menuselect++; } keypressed = 1; ds = 1; } if (keys[SDLK_UP] && (!keypressed)) { menuselect--; while (menu[menuselect].index == 0 && menuselect >= 0) menuselect--; if (menuselect == -1) menuselect = 20; keypressed = 1; ds = 1; } if (keys[SDLK_RETURN] && (!keypressed)) { if (menuselect == 0 && !gserv) { gserv = 1; if (gamesrv_startudp () == -1) return; gamesrv_browse (1); } else done=1; keypressed = 1; } if (event.type == SDL_KEYUP) keypressed = 0; else if (event.type == SDL_KEYDOWN) keypressed = 1; if (i) { draw_logo (); draw_menu ("Select Server", menu, &bx, &by); draw_select (menuselect, menu, bx, by); ds = 0; SDL_Flip (gfx.screen); } else if (ds) { draw_select (menuselect, menu, bx, by); ds = 0; SDL_Flip (gfx.screen); } s_delay (25); } if (menuselect > 0 && menuselect < 10) { i = (menuselect - 1); if (gse[i].name[0] != 0 && gse[i].host[0] != 0 && gse[i].port[0] != 0 && (gse[i].state == GS_wait || gse[i].state == GS_running || gse[i].state == GS_ready)) { /* add if we are on Linux + and Windows and ai_family == PF_INET */ #ifdef _WIN32 if (gse[i].ai_family == PF_INET) { sprintf (bman.servername, "%s:%s", gse[i].host, gse[i].port); bman.net_ai_family = gse[i].ai_family; } #else sprintf (bman.servername, "%s:%s", gse[i].host, gse[i].port); d_printf("%s xxx %s xxx %s",gse[i].host,gse[i].port,bman.servername); bman.net_ai_family = gse[i].ai_family; #endif } } else if (menuselect >= 11 && menuselect < 19) /* User defined Servers */ strncpy (bman.servername, bman.serverlist[menuselect - 11].name, LEN_SERVERNAME + LEN_PORT + 2); else if (menuselect == 20) { /* enter address */ menu_get_text ("Enter Address", bman.servername, LEN_SERVERNAME + LEN_PORT + 2);} if (gserv) { gamesrv_browse (0); udp_close (sock); sock = -1; #ifdef _WIN32 WSACleanup (); #endif } }; int gamesrv_getglist () { int i, i1, i2, i3, y, nr, rebuild = 0; char buf[BUF_SIZE]; char *pos; char txt[255]; struct _sockaddr addr; struct game_entry entry; while (udp_get (sock, buf, BUF_SIZE, &addr, PF_INET) > 0) { d_printf ("GOT:\n%s\n", buf); if (buf[0] == 'E') { for (i = 0; i < MAX_GAMESRVENTRYS; i++) { gse[i].name[0] = 0; gse[i].host[0] = 0; gse[i].port[0] = 0; } for (i = 0; i < 10; i++ ) { menu[i].index = 0; menu[i].text[0] = 0; } sprintf (menu[0].text, "No Games found on Masterserver"); menu[0].index = 1; rebuild = 1; if (menuselect<10) menuselect=0; } else { for (pos = buf; pos != 0;) { // go throught the incoming data switch (pos[0]) { case ('P'): sscanf (pos + 1, "%d,%d", &i1, &i2); entry.curplayers = i1; entry.maxplayers = i2; break; case ('V'): sscanf (pos + 1, "%d.%d.%d", &i1, &i2, &i3); entry.version.major = i1; entry.version.minor = i2; entry.version.sub = i3; break; case ('S'): sscanf (pos + 1, "%d,%d,%d", &i1, &i2, &i3); entry.state = i1; entry.multitype = i2; entry.gametype = i3; break; case ('I'): if (pos[1] == '4') entry.ai_family = PF_INET; else if (pos[1] == '6') #ifndef _WIN32 entry.ai_family = PF_INET6; #else entry.ai_family = 0; #endif break; case ('N'): for (i = 1; (i - 1 < LEN_GAMENAME) && (pos[i] != 0) && (pos[i] != '\n'); i++) entry.name[i - 1] = pos[i]; entry.name[i-1]=0; break; case ('H'): for (i = 1; (i - 1 < LEN_SERVERNAME) && (pos[i] != 0) && (pos[i] != '\n'); i++) entry.host[i - 1] = pos[i]; entry.host[i-1]=0; break; case ('O'): for (i = 1; (i - 1 < LEN_PORT) && (pos[i] != 0) && (pos[i] != '\n'); i++) entry.port[i - 1] = pos[i]; entry.port[i-1]=0; break; } pos = strchr (pos, '\n'); if (pos != 0) pos++; if (pos != 0 && pos[0] == 0) pos = 0; } nr = gamesrv_findentry (entry.host, entry.port); if (nr == -1) { nr = gamesrv_findfree (); if (nr == -1) return -1; } gse[nr] = entry; sprintf (txt, "%16s ", gse[nr].name); if (gse[nr].state == GS_wait) sprintf (txt, "%s Wait ", txt); else if (gse[nr].state == GS_running || gse[nr].state == GS_ready) sprintf (txt, "%sRunning ", txt); else if (gse[nr].state == GS_update) sprintf (txt, "%s Update ", txt); sprintf (txt, "%s%d/%d ", txt, gse[nr].curplayers, gse[nr].maxplayers); if (gse[nr].ai_family == PF_INET) sprintf (txt, "%s %d.%d.%d IPv4", txt, gse[nr].version.major, gse[nr].version.minor, gse[nr].version.sub); else sprintf (txt, "%s %d.%d.%d IPv6", txt, gse[nr].version.major, gse[nr].version.minor, gse[nr].version.sub); for (y = 0; y < 255; y++) menu[nr + 1].text[y] = 0; strncpy (menu[nr + 1].text, txt, 40); rebuild = 1; sprintf (menu[0].text, "Games on the Masterserver"); menu[0].index = 0; if (menuselect == 0) menuselect = 1; menu[nr + 1].index = 1; } } return rebuild; } int gamesrv_startudp () { #ifdef _WIN32 WSADATA wsaData; if (WSAStartup (MAKEWORD (1, 1), &wsaData) != 0) { d_printf ("WSAStartup failed.\n"); exit (1); } #endif sock = udp_server (DEFAULT_GMUDPPORT, bman.net_ai_family); if (sock == -1) { #ifdef _WIN32 WSACleanup (); #endif } return sock; } /* find the entry */ int gamesrv_findentry (char *host, char *port) { int i, y; for (i = 0, y = -1; (i < MAX_GAMESRVENTRYS) && (y == -1); i++) { if (strcmp (gse[i].host, host) == 0 && strcmp (gse[i].port, port) == 0) y = i; } return y; }; /* Find first free entry */ int gamesrv_findfree () { int i, y; for (i = 0, y = -1; (y == -1) && (i < MAX_GAMESRVENTRYS); i++) if (gse[i].host[0] == 0) y = i; return y; }; /* Add and Delete Browsers from Serverbrowselist */ void gamesrv_browse (int i) { char data[255]; struct _sockaddr addr; char host[LEN_SERVERNAME]; char port[LEN_PORT]; d_printf ("** Notify Browser Master Server\n"); if (i) sprintf (data, "B\n"); else sprintf (data, "E\n"); network_server_port (bman.gamemaster, host, LEN_SERVERNAME, port, LEN_PORT); dns_filladdr (host, LEN_SERVERNAME, port, LEN_PORT, bman.net_ai_family, &addr); udp_send (sock, data, strlen (data), &addr, bman.net_ai_family); d_printf ("Send: %s\n", data); }; /* The Server should know that we quit. Delete every entry from our client. */ void gamesrv_quit () { char data[255]; struct _sockaddr addr; char host[LEN_SERVERNAME]; char port[LEN_PORT]; int len; d_printf ("** Notify GameMaster Server\n"); sprintf (data, "D\n"); len = 4; network_server_port (bman.gamemaster, host, LEN_SERVERNAME, port, LEN_PORT); dns_filladdr (host, LEN_SERVERNAME, port, LEN_PORT, bman.net_ai_family, &addr); udp_send (bman.sock, data, len, &addr, bman.net_ai_family); d_printf ("** Send \n\n%s\n\n", data); }; /* send the mode of the game from the current bman.state and bman.gamename parameter */ void gamesrv_sendmode (int maxplayer, int curplayers) { char data[255]; int len = 0; struct _sockaddr addr; char host[LEN_SERVERNAME]; char port[LEN_PORT]; d_printf ("** Notify GameMaster Server\n"); sprintf (data, "AV%s\n", VERSION); sprintf (data, "%sP%d,%d\n", data, curplayers, maxplayer); sprintf (data, "%sS%d,%d,%d\n", data, bman.state, bman.multitype, bman.gametype); if (bman.net_ai_family == PF_INET) sprintf (data, "%sI4\n", data); else sprintf (data, "%sI6\n", data); sprintf (data, "%sN%s\n", data, bman.gamename); len = strlen (data); network_server_port (bman.gamemaster, host, LEN_SERVERNAME, port, LEN_PORT); dns_filladdr (host, LEN_SERVERNAME, port, LEN_PORT, bman.net_ai_family, &addr); host[0] = 0; port[0] = 0; dns_filladdr (host, LEN_SERVERNAME, port, LEN_PORT, bman.net_ai_family, &addr); udp_send (bman.sock, data, len, &addr, bman.net_ai_family); d_printf ("** Send To (%s[:%s])\n\n%s\n\n", host, port, data); }; void gamesrv_sendchat (char *text) { char data[255]; struct _sockaddr addr; char host[LEN_SERVERNAME]; char port[LEN_PORT]; network_server_port (bman.gamemaster, host, LEN_SERVERNAME, port, LEN_PORT); dns_filladdr (host, LEN_SERVERNAME, port, LEN_PORT, bman.net_ai_family, &addr); sprintf (data, "C%s", text); udp_send (bman.sock, data, strlen (data), &addr, bman.net_ai_family); };