/* network commands and data */ #include "basic.h" #include "bomberclone.h" #include "network.h" #include "packets.h" #include "chat.h" #include "sound.h" #include "menu.h" extern _point debug_field; extern int debug_lastping; static short int pkg_lastid; /* the packet id, this will only counted * up nothing more.. if we are at 0x10000 * we will start at 0 */ struct _resend_cache resend_cache; struct _inpkg_index inpkg_index[PKG_IN_INDEX_NUM]; int inpkg_index_pos = 0; /*** *** help function to get the playernumber from the address. *** this function does not indicate which player it is, this function only checks *** if the packet comed from a known player ***/ int get_player_nr (char *host, char *port) { int i, res; for (i = 0, res = -1; (i < MAX_PLAYERS && res == -1); i++) { if (players[i].net.addr.host[0] != 0) if ((strcmp (players[i].net.addr.host, host) == 0) && (strcmp (players[i].net.addr.port, port) == 0)) res = i; } return res; } /*** *** Packettype: error ***/ void send_error (_net_addr * addr, char *text) { struct pkg_error p_err; d_printf ("Send Network Error : %s\n", text); strncpy (p_err.text, text, 127); p_err.h.typ = PKG_error; p_err.h.flags = 0; p_err.h.len = HTON16 (sizeof (struct pkg_error)); p_err.nr = 0; send_pkg ((struct pkg *) &p_err, addr); }; int do_error (struct pkg_error *data, _net_addr * addr) { d_printf ("Network Error from %s:%s : '%s'\n", addr->host, addr->port, data->text); network_shutdown (); menu_displaymessage ("Network Error", "Got Error from: %s:%s\nMessage:%s", addr->host, addr->port, data->text); if (data->nr == 1) return -1; else return 0; }; /*** *** Packettype: joingame *** client sends this to the server if he want's to join *** *** 1) check if this package comes from a already joined and known player *** if so: just send the current playerlist back. *** else: *** 2) find free playerslot and add the player there *** 3) send to all players the new playerid ***/ void do_joingame (struct pkg_joingame *p_jg, _net_addr * addr) { _player *pl; int i, vma, vmi, vsu; char text[255]; d_printf ("do_joingame (From:%s:%s Player(name:%s)\n", addr->host, addr->port, p_jg->name); sscanf (VERSION, "%d.%d.%d", &vma, &vmi, &vsu); /* Do some basic checks befor we accept this data packet * 1) check if we are a server */ if (GT_MP_PTPS) { sprintf (text, "Sorry this is a client and not a server."); send_error (addr, text); return; } /* 2) check the version */ if (p_jg->ver_sub != vsu || p_jg->ver_major != vma || p_jg->ver_minor != vmi) { sprintf (text, "Version Error - Host/Server Version: %s", VERSION); send_error (addr, text); return; } /* 3) check if we have a password */ d_printf ("Password Check Server:\"%s\" Client:\"%s\" %d, %d\n", bman.password, p_jg->password, strlen (bman.password), strlen (p_jg->password)); if (bman.passwordenabled && (strncmp (bman.password, p_jg->password, LEN_PASSWORD) || strlen (bman.password) != strlen (p_jg->password))) { send_error (addr, "This game is Password protected. Your Password is wrong."); return; } /* find a free place for the player and add the player to the game */ if (GS_WAITRUNNING && GT_MP_PTPM) { int j, freeslot; /* find a free playerslot and check if this player isn't already in the list */ for (i = -1, freeslot = -1, j = 0; j < MAX_PLAYERS; j++) { if (!PS_IS_used (players[j].state) && freeslot == -1) freeslot = j; if (strncmp (players[j].net.addr.host, addr->host, LEN_SERVERNAME) == 0 && strncmp (players[j].net.addr.port, addr->port, LEN_PORT) == 0) i = j; } if (i == -1) i = freeslot; if ((i >= 0) && (i < MAX_PLAYERS) && (i < bman.maxplayer)) { /* free player slot found ... fill in data */ pl = &players[i]; pl->state = PSF_used + PSF_net; if (strncmp (pl->name, p_jg->name, LEN_PLAYERNAME) == 0) d_printf (" Player ReJoined : Nr:[%d] Name:%10s\n", i, p_jg->name); else { d_printf (" Player Added : Nr:[%d] Name:%10s\n", i, p_jg->name); pl->points = 0; pl->wins = 0; pl->team_nr = -1; team_choose (pl); } strncpy (pl->name, p_jg->name, LEN_PLAYERNAME); pl->gfx_nr = -1; pl->gfx = NULL; pl->state &= (0xFF - (PSF_alife + PSF_playing)); /* Reset the network data */ pl->net.timestamp = timestamp; pl->net.pkgopt.to_timestamp = timestamp; pl->net.pkgopt.to_2sec = 0; pl->net.pkgopt.send_to = 0; pl->net.pkgopt.send_set = PKG_SENDSETOPT; strncpy (pl->net.addr.host, addr->host, LEN_SERVERNAME); strncpy (pl->net.addr.port, addr->port, LEN_PORT); dns_filladdr (pl->net.addr.host, LEN_SERVERNAME, pl->net.addr.port, LEN_PORT, bman.net_ai_family, &pl->net.addr.sAddr); if (p_jg->secondplayer) pl->net.flags = NETF_local2 + NETF_firewall; else pl->net.flags = NETF_firewall; pl->net.addr.pl_nr = i; bman.players_nr_s++; /* send to the new client the servermode and the complete playerlist */ send_mapinfo (addr); send_servermode (addr, i); // with this packet the client know it'S pl_nr addr->pl_nr = i; /* Send all connected players the new PlayerID, except to the new player */ for (i = 0; i < MAX_PLAYERS; i++) if (NET_CANSEND(i) && addr->pl_nr != i) send_playerid (&players[i].net.addr, pl->name, pl->net.addr.host, pl->net.addr.port, pl->net.addr.pl_nr, pl->gfx_nr, pl->team_nr, pl->net.flags); } else if (GS_WAITRUNNING) { send_error (addr, "No Free Playerslot found\n"); return; } else if (!GS_WAITRUNNING) { send_error (addr, "Update mode, please try again.\n"); return; } } d_playerdetail ("*** PLAYER List ***"); bman.updatestatusbar = 1; }; void send_joingame (_net_addr * addr, char *name, int secondplayer) { struct pkg_joingame p_jg; int vmi, vma, vsu; d_printf ("send_joingame SendTo: %s:%s (Name:%16s)\n", addr->host, addr->port, name); sscanf (VERSION, "%d.%d.%d", &vma, &vmi, &vsu); p_jg.h.typ = PKG_joingame; p_jg.h.flags = PKGF_ackreq; p_jg.h.len = HTON16 (sizeof (struct pkg_joingame)); p_jg.ver_sub = vsu; p_jg.ver_major = vma; p_jg.ver_minor = vmi; p_jg.secondplayer = secondplayer; strncpy (p_jg.name, name, LEN_PLAYERNAME); strncpy (p_jg.password, bman.password, LEN_PASSWORD); send_pkg ((struct pkg *) &p_jg, addr); }; /*** *** Packettype: contest *** Test the connection from a new player for the firewall flag. *** This packet will be send from one player to the other the *** current server will only get this packet if a connection test was positive ***/ void do_contest (struct pkg_contest *ct_pkg, _net_addr *addr) { d_printf ("do_contest (pl_nr = %d) from=%d to=%d\n", addr->pl_nr, ct_pkg->from, ct_pkg->to); if (addr->pl_nr >= MAX_PLAYERS || (addr->pl_nr == -1 && PS_IS_netplayer(players[ct_pkg->from].state))) { d_printf (" addr->pl_nr out of range (0-MAX_PLAYERS)\n"); return; } /* master will have to change the firewall flag on a player */ if (GT_MP_PTPM) { if (ct_pkg->from < 0 || ct_pkg->from >= MAX_PLAYERS) { if ((ct_pkg->to < 0 || ct_pkg->to >= MAX_PLAYERS) && addr->pl_nr != ct_pkg->from) d_printf (" from or to value out of range (0-MAX_PLAYERS)\n"); return; } players[ct_pkg->to].net.flags &= (0xFF - NETF_firewall); net_game_send_player (ct_pkg->to); } /* if a client get this packet we send a packet * to the server that we have got this packet. */ else send_contest (&players[bman.p_servnr].net.addr, ct_pkg->from, bman.p_nr, 1); } void send_contest (_net_addr * addr, int from, int to, int ackreq) { struct pkg_contest ct_pkg; d_printf ("send_contest addr->id%d, from:%d, to:%d\n", addr->pl_nr, from, to); ct_pkg.h.typ = PKG_contest; if (ackreq) ct_pkg.h.flags = PKGF_ackreq; else ct_pkg.h.flags = 0; ct_pkg.h.len = HTON16 (sizeof (struct pkg_contest)); ct_pkg.from = from; ct_pkg.to = to; send_pkg ((struct pkg *) &ct_pkg, addr); } /*** *** Packettype: playerid *** Update Playerinformation, Teampoints of a Player, Points *** *** *** if : the pl_nr == -1 send the whole list to the sender *** else: set the new values for this player ***/ void do_playerid (struct pkg_playerid *p_id, _net_addr * addr) { _player *pl; int i; d_printf ("do_playerid (From:%s:%s pl_nr=%d) Player(name:%s [%s:%s], pl_nr:%d)\n", addr->host, addr->port, addr->pl_nr, p_id->name, p_id->host, p_id->port, p_id->pl_nr); /* * check if we have to send the whole playerlist to a client */ if (GT_MP_PTPM && p_id->pl_nr == -1) { for (i = 0; i < MAX_PLAYERS; i++) send_playerid (addr, players[i].name, players[i].net.addr.host, players[i].net.addr.port, i, players[i].gfx_nr, players[i].team_nr, players[i].net.flags); } /* * check if we have to update someones data */ else if ((GT_MP_PTPM && p_id->pl_nr >= 0 && p_id->pl_nr < MAX_PLAYERS && p_id->pl_nr != bman.p_nr && p_id->pl_nr != bman.p2_nr) || (GT_MP_PTPS && p_id->pl_nr >= 0 && p_id->pl_nr < MAX_PLAYERS)) { pl = &players[p_id->pl_nr]; pl->net.timestamp = timestamp; pl->net.pingreq = pl->net.pingack + 5; if (GT_MP_PTPS) pl->net.flags = p_id->netflags; if (p_id->host[0] != 0) { pl->net.addr.pl_nr = addr->pl_nr; strncpy (pl->net.addr.host, p_id->host, LEN_SERVERNAME); strncpy (pl->net.addr.port, p_id->port, LEN_PORT); dns_filladdr (pl->net.addr.host, LEN_SERVERNAME, pl->net.addr.port, LEN_PORT, bman.net_ai_family, &pl->net.addr.sAddr); } /* player is used, we need to check if it's the second player from the server * to set it's host and port name */ else if (PS_IS_used (p_id->state)) { strncpy (pl->net.addr.host, players[bman.p_servnr].net.addr.host, LEN_SERVERNAME); strncpy (pl->net.addr.port, players[bman.p_servnr].net.addr.port, LEN_PORT); memcpy (&pl->net.addr.sAddr, &players[bman.p_servnr].net.addr.sAddr, sizeof (struct _sockaddr)); } /* Check if we have to make a network test.. only client to client */ if (GT_MP_PTPS && !(PS_IS_netplayer (pl->state)) && (PS_IS_netplayer (p_id->state)) && p_id->pl_nr != bman.p_servnr && p_id->pl_nr != bman.p_nr) { send_contest (&pl->net.addr, bman.p_nr, -1, 0); // send contest without ackreq. /* make sure we still get messages from the server, this is a * work around for some hardware routers */ send_contest (&players[bman.p_servnr].net.addr, bman.p_nr, -1, 1); } pl->state = p_id->state; if (p_id->pl_nr != bman.p_nr && PS_IS_used (pl->state)) pl->state |= PSF_net; else pl->state &= (0xff - PSF_net); if (pl->gfx_nr != p_id->gfx_nr) player_set_gfx (pl, p_id->gfx_nr); strncpy (pl->name, p_id->name, LEN_PLAYERNAME); if (GT_MP_PTPS) { pl->points = NTOH16 (p_id->points); pl->wins = NTOH16 (p_id->wins); pl->team_nr = p_id->team_nr; if (pl->team_nr >= 0 && pl->team_nr < MAX_TEAMS) { teams[pl->team_nr].points = NTOH16(p_id->team_points); teams[pl->team_nr].wins = NTOH16(p_id->team_wins); } } /* Send all connected players the new PlayerID */ if (GT_MP_PTPM && GS_WAITRUNNING && addr->pl_nr >= 0 && addr->pl_nr < MAX_PLAYERS) net_change_playerid (addr->pl_nr); } // d_playerdetail ("*** PLAYER List ***"); team_update (); bman.updatestatusbar = 1; }; void send_playerid (_net_addr * addr, char *name, char *pladdr, char *plport, int pl_nr, int gfx_nr, int team_nr, signed char netflags) { struct pkg_playerid p_id; d_printf ("send_playerid SendTo: %s:%s (Name:%16s p_nr:%d)\n", addr->host, addr->port, name, pl_nr); p_id.h.typ = PKG_playerid; p_id.h.flags = PKGF_ackreq; p_id.h.len = HTON16 (sizeof (struct pkg_playerid)); if (name != NULL) strncpy (p_id.name, name, LEN_PLAYERNAME); else p_id.name[0] = 0; if (pladdr == NULL) p_id.host[0] = 0; else strncpy (p_id.host, pladdr, LEN_SERVERNAME); if (plport == NULL) p_id.port[0] = 0; else strncpy (p_id.port, plport, LEN_PORT); p_id.pl_nr = pl_nr; p_id.netflags = netflags; p_id.gfx_nr = gfx_nr; if (pl_nr != -1) { p_id.points = HTON16 (players[pl_nr].points); p_id.wins = HTON16 (players[pl_nr].wins); p_id.state = players[pl_nr].state; p_id.team_nr = team_nr; if (team_nr >= 0 && team_nr < MAX_TEAMS) { p_id.team_points = teams[team_nr].points; p_id.team_wins = teams[team_nr].wins; } } else { p_id.points = 0; p_id.wins = 0; p_id.state = 0; p_id.team_nr = -1; p_id.team_points = 0; p_id.team_wins = 0; } send_pkg ((struct pkg *) &p_id, addr); }; /*** *** Packettype: servermode ***/ void do_servermode (struct pkg_servermode *s_mod, _net_addr * addr) { if (addr->pl_nr == -1) return; d_printf ("do_servermode (%s:%s) state = %d\n", addr->host, addr->port, s_mod->state); /* if we just have connected the bman.p_nr is still -1, so we handle the servermode packet still alittle diffrent */ if ((!s_mod->lplayer2 && bman.p_nr == -1) || (s_mod->lplayer2 && bman.p2_nr == -1)) { d_printf (" Server gave us: p_nr: %d(old:%d), p_servnr: %d(old:%d)\n", s_mod->p_nr,bman.p_nr, s_mod->p_servnr, bman.p_servnr); /* set the p_servnr to the playerslot which is the server */ if (bman.p_servnr != s_mod->p_servnr) { memcpy (&players[s_mod->p_servnr].net, &players[bman.p_servnr].net, sizeof (_net_player)); bzero (&players[bman.p_servnr], sizeof (_net_player)); bman.p_servnr = s_mod->p_servnr; } /* set now the new p_nr number */ if (s_mod->p_nr >= 0 && s_mod->p_nr < MAX_PLAYERS && bman.p_nr == -1 && s_mod->lplayer2 == 0) { bman.p_nr = s_mod->p_nr; bman.firewall = 1; players[bman.p_nr].net.flags = NETF_firewall; players[bman.p_nr].state &= (0xFF - PSF_net); strncpy (players[s_mod->p_nr].name, bman.playername, LEN_PLAYERNAME); } else if (s_mod->p_nr >= 0 && s_mod->p_nr < MAX_PLAYERS && bman.p2_nr == -1 && s_mod->lplayer2 == 1) { bman.p2_nr = s_mod->p_nr; players[bman.p2_nr].net.flags = NETF_firewall + NETF_local2; players[bman.p2_nr].state &= (0xFF - PSF_net); strncpy (players[s_mod->p_nr].name, bman.player2name, LEN_PLAYERNAME); } /* send playerid with p_nr -1 so we get the whole playerlist */ send_playerid (addr, NULL, NULL, NULL, -1, -1, -1, 0); } /* do the normal update */ if (GT_MP_PTPS) { bman.state = s_mod->state; bman.gametype = s_mod->gametype; bman.dropitemsondeath = s_mod->dropitemsondeath; map.state = s_mod->mapstate; bman.players_nr_s = s_mod->players; bman.lastwinner = s_mod->last_winner; map.size.x = s_mod->fieldsize_x; map.size.y = s_mod->fieldsize_y; strncpy (map.tileset, s_mod->tileset, LEN_TILESETNAME); } bman.updatestatusbar = 1; }; void send_servermode (_net_addr * addr, int pl_nr) { struct pkg_servermode s_mod; s_mod.h.typ = PKG_servermode; s_mod.h.len = HTON16 (sizeof (struct pkg_servermode)); s_mod.h.flags = PKGF_ackreq; s_mod.type = bman.gametype; s_mod.dropitemsondeath = bman.dropitemsondeath; s_mod.mapstate = map.state; if (bman.state == GS_quit) /* do not send GS_quit */ s_mod.state = GS_startup; else s_mod.state = bman.state; s_mod.gametype = bman.gametype; s_mod.players = bman.players_nr_s; s_mod.maxplayer = bman.maxplayer; s_mod.p_nr = pl_nr; if (pl_nr >= 0 && pl_nr < MAX_PLAYERS && (players[pl_nr].net.flags & NETF_local2) == NETF_local2) s_mod.lplayer2 = 1; else s_mod.lplayer2 = 0; s_mod.p_servnr = bman.p_servnr; s_mod.last_winner = bman.lastwinner; s_mod.fieldsize_x = map.size.x; s_mod.fieldsize_y = map.size.y; strncpy (s_mod.tileset, map.tileset, LEN_TILESETNAME); switch (s_mod.state) { case (GS_startup): d_printf ("Send ServerMode : startup\n"); break; case (GS_ready): d_printf ("Send ServerMode : ready\n"); break; case (GS_running): d_printf ("Send ServerMode : running\n"); break; case (GS_quit): d_printf ("Send ServerMode : quit\n"); break; case (GS_wait): d_printf ("Send ServerMode : wait\n"); break; case (GS_update): d_printf ("Send ServerMode : wait\n"); break; } send_pkg ((struct pkg *) &s_mod, addr); }; /*** *** Packettype: field ***/ void send_field (_net_addr * addr, int x, int y, _field * field) { struct pkg_field f_dat; int i; d_printf ("send_field [%d,%d]\n", x, y); f_dat.h.typ = PKG_field; f_dat.h.len = HTON16 (sizeof (struct pkg_field)); f_dat.h.flags = PKGF_ackreq; f_dat.x = x; f_dat.y = y; if (x < 0 || x >= map.size.x || y < 0 || y >= map.size.y) return; for (i = 0; i < 4; i++) { f_dat.ex[i].count = map.field[x][y].ex[i].count; f_dat.ex[i].frame = (int) map.field[x][y].ex[i].frame; f_dat.ex[i].bomb_p = map.field[x][y].ex[i].bomb_p; f_dat.ex[i].bomb_b = map.field[x][y].ex[i].bomb_b; } f_dat.type = map.field[x][y].type; f_dat.mixframe = map.field[x][y].mixframe; f_dat.special = map.field[x][y].special; f_dat.frame = HTON16 (FTOI16 (map.field[x][y].frame)); f_dat.ex_nr = HTON32 (map.field[x][y].ex_nr); send_pkg ((struct pkg *) &f_dat, addr); }; void do_field (struct pkg_field *f_dat, _net_addr * addr) { int i; if (addr->pl_nr == -1) return; if (f_dat->x < map.size.x && f_dat->y < map.size.y) { /* convert the fielddata */ map.field[f_dat->x][f_dat->y].type = f_dat->type; map.field[f_dat->x][f_dat->y].mixframe = f_dat->mixframe; map.field[f_dat->x][f_dat->y].special = f_dat->special; for (i = 0; i < 4; i++) { /* set the explosion field data */ map.field[f_dat->x][f_dat->y].ex[i].count = f_dat->ex[i].count; map.field[f_dat->x][f_dat->y].ex[i].frame = f_dat->ex[i].frame; map.field[f_dat->x][f_dat->y].ex[i].bomb_p = f_dat->ex[i].bomb_p; map.field[f_dat->x][f_dat->y].ex[i].bomb_b = f_dat->ex[i].bomb_b; } map.field[f_dat->x][f_dat->y].frame = I16TOF (NTOH16 (f_dat->frame)); map.field[f_dat->x][f_dat->y].ex_nr = NTOH32 (f_dat->ex_nr); } if (bman.state == GS_running) stonelist_add (f_dat->x, f_dat->y); if (NTOH32 (f_dat->ex_nr) > bman.last_ex_nr) bman.last_ex_nr = NTOH32 (f_dat->ex_nr); d_printf ("do_field (%d,%d) ex_nr = %d, special = %d, type = %d\n", f_dat->x, f_dat->y, NTOH32 (f_dat->ex_nr), f_dat->special, f_dat->type); }; /*** *** Packettype: pingack/pingreq ***/ void do_ping (struct pkg_ping *p_dat, _net_addr * addr) { if (addr->pl_nr == -1) return; if (p_dat->h.typ == PKG_pingack) /* ping was an answer */ players[addr->pl_nr].net.pingack = NTOH32 (p_dat->data); else /* send the answer */ send_ping (addr, NTOH32 (p_dat->data), PKG_pingack); d_printf ("do_ping pl_nr[%d] (%s:%s) req=%d, ack=%d\n", addr->pl_nr, addr->host, addr->port, players[addr->pl_nr].net.pingreq, players[addr->pl_nr].net.pingack); }; void send_ping (_net_addr * addr, int data, unsigned char typ) { struct pkg_ping p_dat; if (addr->pl_nr == -1) return; p_dat.h.len = HTON16 (sizeof (struct pkg_ping)); p_dat.h.flags = 0; if (typ == PKG_pingack) { p_dat.h.typ = typ; p_dat.data = HTON32 (data); send_pkg ((struct pkg *) &p_dat, addr); } else if (typ == PKG_pingreq) { p_dat.h.typ = typ; p_dat.data = HTON32 (data); send_pkg ((struct pkg *) &p_dat, addr); } d_printf ("send_ping Player[%d] (%s:%s) req=%d, ack=%d\n", addr->pl_nr, addr->host, addr->port, players[addr->pl_nr].net.pingreq, players[addr->pl_nr].net.pingack); players[addr->pl_nr].net.timestamp = timestamp; /* we need to set it here, so we can check for the timeout again */ }; /*** *** Packettype: playerdata ***/ void send_playerdata (_net_addr * addr, int p_nr, _player * pl) { struct pkg_playerdata p_dat; p_dat.h.typ = PKG_playerdata; p_dat.h.len = HTON16 (sizeof (struct pkg_playerdata)); if (bman.state == GS_update) p_dat.h.flags = 0; else p_dat.h.flags = PKGF_ackreq; p_dat.pos.x = HTON16 (FTOI16 (pl->pos.x)); p_dat.pos.y = HTON16 (FTOI16 (pl->pos.y)); p_dat.bombs_n = pl->bombs_n; p_dat.d = pl->d; p_dat.range = pl->range; p_dat.gfx_nr = pl->gfx_nr; p_dat.state = pl->state; p_dat.wins = HTON16 (pl->wins); p_dat.points = HTON16 (pl->points); p_dat.dead_by = pl->dead_by; p_dat.frame = HTON16 (FTOI16 (pl->frame)); p_dat.p_nr = p_nr; p_dat.ready = pl->ready; send_pkg ((struct pkg *) &p_dat, addr); }; void do_playerdata (struct pkg_playerdata *p_dat, _net_addr * addr) { _player *pl; if (addr->pl_nr == -1) return; if (p_dat->p_nr < 0 || p_dat->p_nr >= MAX_PLAYERS) return; d_printf ("do_playerdata (From: %d) p_nr: %d\n", addr->pl_nr, p_dat->p_nr); bman.updatestatusbar = 1; // force an update pl = &players[p_dat->p_nr]; player_set_gfx (pl, p_dat->gfx_nr); if (bman.state == GS_running && bman.p_nr != p_dat->p_nr) { pl->points = NTOH16 (p_dat->points); pl->dead_by = NTOH16 (p_dat->dead_by); } else if (bman.state != GS_running || bman.p_nr != p_dat->p_nr) { pl->pos.x = I16TOF (NTOH16 (p_dat->pos.x)); pl->pos.y = I16TOF (NTOH16 (p_dat->pos.y)); pl->dead_by = p_dat->dead_by; pl->points = NTOH16 (p_dat->points); pl->d = p_dat->d; pl->bombs_n = p_dat->bombs_n; pl->range = p_dat->range; pl->frame = I16TOF (NTOH16 (p_dat->frame)); pl->state = p_dat->state; pl->team_nr = p_dat->team_nr; pl->ready = p_dat->ready; team_update (); } if (p_dat->dead_by < 0 || p_dat->dead_by >= MAX_PLAYERS) /* set player state no matter what */ pl->state = p_dat->state; else { /* player died in the game */ /* check if the player just died */ if (PS_IS_alife (pl->state) && PS_IS_dead (p_dat->state)) { /* player just died */ if (p_dat->p_nr != p_dat->dead_by) { players[p_dat->dead_by].points++; if (bman.gametype == GT_team && players[p_dat->dead_by].team_nr >= 0 && players[p_dat->dead_by].team_nr < MAX_TEAMS) teams[players[p_dat->dead_by].team_nr].points++; net_game_send_player (p_dat->dead_by); } } pl->state = p_dat->state; } /* set the state of the player */ if (p_dat->p_nr != bman.p_nr && PS_IS_used (pl->state)) pl->state |= PSF_net; else pl->state &= (0xff - PSF_net); if (p_dat->gfx_nr == -1) pl->state &= (0xff - PSF_alife); if (bman.state == GS_update && PS_IS_used (p_dat->state)) bman.players_nr_s++; if (players[bman.p_nr].net.net_istep == 1) players[bman.p_nr].net.net_status = p_dat->p_nr; } /*** *** Packettype: ill ***/ void do_ill (struct pkg_ill *ill, _net_addr * addr) { int i, old_to; if (addr->pl_nr == -1) return; d_printf ("do_ill (From: %d) For Player %d\n", addr->pl_nr, ill->pl_nr); if (ill->pl_nr < 0 || ill->pl_nr >= MAX_PLAYERS || ill->pl_nr == bman.p_nr) return; for (i = 0; i < PI_max; i++) { old_to = players[ill->pl_nr].ill[i].to; players[ill->pl_nr].ill[i].to = I32TOF (NTOH32 (ill->to[i])); if (players[ill->pl_nr].ill[i].to <= 0.0f && old_to > 0.0f) player_clear_ilness (&players[ill->pl_nr], i); else if (players[ill->pl_nr].ill[i].to > 0.0f && old_to <= 0.0f) player_set_ilness (&players[ill->pl_nr], i, players[ill->pl_nr].ill[i].to); d_printf (" to[%d]:%f dataf:%f datai:%d\n", i, players[ill->pl_nr].ill[i].to, players[ill->pl_nr].ill[i].dataf, players[ill->pl_nr].ill[i].datai); } }; void send_ill (_net_addr * addr, int p_nr, _player * pl) { struct pkg_ill ill; int i; ill.h.typ = PKG_ill; ill.h.len = HTON16 (sizeof (struct pkg_ill)); ill.h.flags = PKGF_ackreq; ill.pl_nr = p_nr; for (i = 0; i < PI_max; i++) ill.to[i] = HTON32 (FTOI32 (pl->ill[i].to)); send_pkg ((struct pkg *) &ill, addr); }; /*** *** Packettype: playermove ***/ void send_playermove (_net_addr * addr, int p_nr, _player * pl) { struct pkg_playermove p_dat; p_dat.h.typ = PKG_playermove; p_dat.h.len = HTON16 (sizeof (struct pkg_playermove)); p_dat.h.flags = 0; p_dat.pos.x = HTON16 (FTOI16 (pl->pos.x)); p_dat.pos.y = HTON16 (FTOI16 (pl->pos.y)); p_dat.m = pl->m; p_dat.d = pl->d; p_dat.p_nr = p_nr; p_dat.speed = HTON16 (FTOI16 (pl->speed)); p_dat.tunnelto = HTON16 (FTOI16 (pl->tunnelto)); send_pkg ((struct pkg *) &p_dat, addr); }; void do_playermove (struct pkg_playermove *p_dat, _net_addr * addr) { _player *pl; if (addr->pl_nr == -1) return; if (p_dat->p_nr == -1) return; if (addr->pl_nr == -1) // unknown player return; /* check if the right player is sending the information */ pl = &players[p_dat->p_nr]; pl->m = p_dat->m; pl->d = p_dat->d; pl->speed = I16TOF (NTOH16 (p_dat->speed)); pl->pos.x = I16TOF (NTOH16 (p_dat->pos.x)); pl->pos.y = I16TOF (NTOH16 (p_dat->pos.y)); pl->tunnelto = I16TOF (NTOH16 (p_dat->tunnelto)); } /*** *** Packettype: bombdata ***/ void do_bombdata (struct pkg_bombdata *b_dat, _net_addr * addr) { _bomb *bomb; if (addr->pl_nr == -1) return; if (b_dat->p_nr >= MAX_PLAYERS || b_dat->b_nr >= MAX_BOMBS) { d_printf ("Bomb Error\n"); return; } if (b_dat->state == BS_off) return; // if there was a bomb let it explose don't delete the bomb d_printf ("do_bombdata [%f,%f] Player: %d Bomb: %d, ex_nr:%d\n", I16TOF (NTOH16 (b_dat->x)), I16TOF (NTOH16 (b_dat->y)), b_dat->p_nr, b_dat->b_nr, NTOH32 (b_dat->ex_nr)); bomb = &players[b_dat->p_nr].bombs[b_dat->b_nr]; if (bomb->state == BS_exploding) { d_printf ("do_bombdata ---> bomb is already exploding\n"); return; } if ((bomb->pos.x != NTOH16 (b_dat->x) || bomb->pos.y != NTOH16 (b_dat->y)) && bomb->state == BS_exploding && b_dat->state != BS_exploding) d_printf ("do_bombdata WARNING : bomb explosion haven't finished\n"); if (bomb->state != BS_off) { // handle push & kick special map.bfield[(int) bomb->pos.x][(int) bomb->pos.y] = 0; //remove bomb at old location stonelist_add (bomb->pos.x, bomb->pos.y); stonelist_add (bomb->pos.x + 1, bomb->pos.y); stonelist_add (bomb->pos.x, bomb->pos.y + 1); stonelist_add (bomb->pos.x + 1, bomb->pos.y + 1); } if (bomb->state == BS_off && (b_dat->state == BS_ticking || b_dat->state == BS_trigger)) snd_play (SND_bombdrop); /* convert position back to float */ bomb->pos.x = I16TOF (NTOH16 (b_dat->x)); bomb->pos.y = I16TOF (NTOH16 (b_dat->y)); if (bomb->state != b_dat->state && bomb->state != BS_ticking) bomb->to = I32TOF (NTOH32 (b_dat->to)); /* only set if the bomb isn't already ticking to make sure the timeout won't be resetted by an old network packet */ map.bfield[(int) bomb->pos.x][(int) bomb->pos.y] = 1; // keep the bfield up to date bomb->r = b_dat->r; bomb->ex_nr = NTOH32 (b_dat->ex_nr); bomb->state = b_dat->state & 0x0F; bomb->mode = b_dat->state >> 4; bomb->speed = I16TOF (NTOH16 (b_dat->speed)); bomb->dest.x = NTOH16 (b_dat->destx); bomb->dest.y = NTOH16 (b_dat->desty); if (bomb->state == BS_exploding) bomb_explode (bomb, 0); if (bomb->ex_nr > bman.last_ex_nr) bman.last_ex_nr = bomb->ex_nr; }; void send_bombdata (_net_addr * addr, int p, int b, _bomb * bomb) { struct pkg_bombdata b_dat; b_dat.h.typ = PKG_bombdata; b_dat.h.len = HTON16 (sizeof (struct pkg_bombdata)); b_dat.x = HTON16 (FTOI16 (bomb->pos.x)); b_dat.y = HTON16 (FTOI16 (bomb->pos.y)); b_dat.to = HTON32 (FTOI32 (bomb->to)); b_dat.r = bomb->r; b_dat.ex_nr = HTON32 (bomb->ex_nr); b_dat.state = (bomb->mode << 4) | (bomb->state); b_dat.b_nr = b; b_dat.p_nr = p; b_dat.h.flags = PKGF_ackreq; b_dat.speed = HTON16 (FTOI16 (bomb->speed)); b_dat.destx = HTON16 (bomb->dest.x); b_dat.desty = HTON16 (bomb->dest.y); send_pkg ((struct pkg *) &b_dat, addr); }; /*** *** Packettype: bombdata *** recive a request for some tunneldata or receive tunneldata ***/ void do_tunneldata (struct pkg_tunneldata *tun_pkg, _net_addr * addr) { d_printf ("do_tunneldata: From %d [%s:%s] (Tunnel %d Target [%d,%d])\n", addr->pl_nr, addr->host, addr->port, tun_pkg->tunnel_nr, NTOH16 (tun_pkg->target.x), NTOH16 (tun_pkg->target.y)); if (addr->pl_nr != bman.p_servnr && GT_MP_PTPM && NTOH16 (tun_pkg->target.y) == -1 && NTOH16 (tun_pkg->target.x) == -1) { send_tunneldata (addr, tun_pkg->tunnel_nr, map.tunnel[tun_pkg->tunnel_nr].x, map.tunnel[tun_pkg->tunnel_nr].y); players[addr->pl_nr].net.net_status = tun_pkg->tunnel_nr; players[addr->pl_nr].net.net_istep = 3; } else if (addr->pl_nr == bman.p_servnr && tun_pkg->tunnel_nr < GAME_MAX_TUNNELS) { map.tunnel[tun_pkg->tunnel_nr].x = NTOH16 (tun_pkg->target.x); map.tunnel[tun_pkg->tunnel_nr].y = NTOH16 (tun_pkg->target.y); players[bman.p_nr].net.net_status = tun_pkg->tunnel_nr; } }; /* send a tunneldata request (x && y == -1) or send tunneldata */ void send_tunneldata (_net_addr * addr, int tunnelnr, int x, int y) { struct pkg_tunneldata tun_pkg; d_printf ("send_tunneldata (Tunnel %d Target [%d,%d])\n", tunnelnr, x, y); tun_pkg.h.typ = PKG_tunneldata; tun_pkg.h.flags = PKGF_ackreq; tun_pkg.h.len = HTON16 (sizeof (struct pkg_tunneldata)); if (GT_MP_PTPM || (GT_MP_PTPS && x == -1 && y == -1)) { tun_pkg.tunnel_nr = tunnelnr; tun_pkg.target.x = HTON16 (x); tun_pkg.target.y = HTON16 (y); send_pkg ((struct pkg *) &tun_pkg, addr); } }; /*** *** Packettype: quit ***/ void send_quit (_net_addr * addr, int pl_nr, int new_server) { struct pkg_quit q_dat; d_printf ("send_quit (%s:%s) pl_nr: %d\n", addr->host, addr->port, pl_nr); q_dat.h.typ = PKG_quit; q_dat.h.flags = 0; q_dat.h.len = HTON16 (sizeof (struct pkg_quit)); q_dat.pl_nr = pl_nr; q_dat.new_server = new_server; send_pkg ((struct pkg *) &q_dat, addr); }; void do_quit (struct pkg_quit *q_dat, _net_addr * addr) { d_printf ("do_quit (%s:%s) pl_nr = %d\n", addr->host, addr->port, q_dat->pl_nr); if (addr->pl_nr == -1) return; /* the player who send this quit */ if (addr->pl_nr == bman.p_servnr && q_dat->new_server != bman.p_servnr) { d_printf ("do_quit: new server is set to: %d\n", q_dat->new_server); bman.p_servnr = q_dat->new_server; if (GT_MP_PTPM && bman.notifygamemaster) send_ogc_update (); } bman.updatestatusbar=1; player_delete (q_dat->pl_nr); }; /*** *** Packettype: getfield ***/ void send_getfield (_net_addr * addr, int line) { struct pkg_getfield gf_dat; gf_dat.h.typ = PKG_getfield; gf_dat.h.len = HTON16 (sizeof (struct pkg_getfield)); gf_dat.h.flags = 0; gf_dat.line = line; send_pkg ((struct pkg *) &gf_dat, addr); }; void do_getfield (struct pkg_getfield *gf_dat, _net_addr * addr) { if (addr->pl_nr == -1) return; if (gf_dat->line < 0 || gf_dat->line >= MAX_FIELDSIZE_Y) return; if (addr->pl_nr != -1 && bman.state == GS_update && GT_MP_PTPM) { if (addr->pl_nr != bman.p_servnr && addr->pl_nr < MAX_PLAYERS) { players[addr->pl_nr].net.net_status = gf_dat->line; players[addr->pl_nr].net.net_istep = 2; } } send_fieldline (addr, gf_dat->line); }; /*** *** Packettype: fieldline ***/ void send_fieldline (_net_addr * addr, int line) { int i, j; struct pkg_fieldline f_dat; f_dat.h.typ = PKG_fieldline; f_dat.h.len = HTON16 (sizeof (struct pkg_fieldline)); f_dat.h.flags = 0; f_dat.line = line; if (line < 0 || line >= MAX_FIELDSIZE_Y) return; for (i = 0; i < MAX_FIELDSIZE_X; i++) { f_dat.type[i] = map.field[i][line].type; f_dat.special[i] = map.field[i][line].special; map.field[i][line].frame = 0.0f; map.field[i][line].ex_nr = 0; for (j = 0; j < 4; j++) { map.field[i][line].ex[j].frame = 0.0f; map.field[i][line].ex[j].count = 0; } } send_pkg ((struct pkg *) &f_dat, addr); }; void do_fieldline (struct pkg_fieldline *f_dat, _net_addr * addr) { int i, d; if (addr->pl_nr == -1) return; if (addr->pl_nr != bman.p_servnr) { /* the data we have got are not from the server */ d_printf ("do_fieldline: the data we have got are not from the server\n"); return; } if (f_dat->line < 0 || f_dat->line >= MAX_FIELDSIZE_Y) { /* the line number is wrong */ d_printf ("do_fieldline: the line number is not correct\n"); return; } if (players[bman.p_nr].net.net_istep == 2) players[bman.p_nr].net.net_status = f_dat->line; for (i = 0; i < MAX_FIELDSIZE_X; i++) { map.field[i][f_dat->line].type = f_dat->type[i]; map.field[i][f_dat->line].special = f_dat->special[i]; map.field[i][f_dat->line].frame = 0.0f; for (d = 0; d < 4; d++) { map.field[i][f_dat->line].ex[d].frame = 0.0f; map.field[i][f_dat->line].ex[d].count = 0; } } }; /*** *** Packettype: getplayerdata ***/ void send_getplayerdata (_net_addr * addr, int pl) { struct pkg_getplayerdata gp_dat; gp_dat.h.typ = PKG_getplayerdata; gp_dat.h.len = HTON16 (sizeof (struct pkg_getplayerdata)); gp_dat.pl_nr = pl; gp_dat.h.flags = 0; send_pkg ((struct pkg *) &gp_dat, addr); }; void do_getplayerdata (struct pkg_getplayerdata *gp_dat, _net_addr * addr) { if (addr->pl_nr == -1) return; if (gp_dat->pl_nr < 0 || gp_dat->pl_nr >= MAX_PLAYERS) return; if (addr->pl_nr != -1 && bman.state == GS_update && GT_MP_PTPM) { if (addr->pl_nr != bman.p_servnr && addr->pl_nr < MAX_PLAYERS) { players[addr->pl_nr].net.net_status = gp_dat->pl_nr; players[addr->pl_nr].net.net_istep = 1; } } send_playerdata (addr, gp_dat->pl_nr, &players[gp_dat->pl_nr]); }; /*** *** Packettype: playerstatus ***/ void do_playerstatus (struct pkg_playerstatus *stat, _net_addr * addr) { d_printf ("do_playerstatus (%s,%s)\n", addr->host, addr->port); if (addr->pl_nr != bman.p_servnr && !(GT_MP_PTPM)) { /* the data we have got are not from the server */ d_printf ("do_playerstatus: the data we have got are not from the server\n"); return; } if (stat->pl_nr < 0 || stat->pl_nr >= MAX_PLAYERS) { /* the player number is wrong */ d_printf ("do_playerstatus: playernumber not correct\n"); return; } players[addr->pl_nr].net.net_status = stat->status; players[addr->pl_nr].net.net_istep = stat->net_istep; /* if (GT_MP_PTPM) for (i = 0; i < MAX_PLAYERS; i++) if (players[i].net.addr.host[0] != 0) send_playerstatus (addr, stat->pl_nr, stat->net_istep, stat->status); */ }; void send_playerstatus (_net_addr * addr, int pl_nr, int net_istep, int status) { struct pkg_playerstatus stat; d_printf ("send_playerstatus (%s,%s) %d, %d, %d\n", addr->host, addr->port, pl_nr, net_istep, status); stat.h.typ = PKG_playerstatus; stat.h.flags = 0; stat.h.len = HTON16 (sizeof (struct pkg_playerstatus)); stat.pl_nr = pl_nr; stat.net_istep = net_istep; stat.status = status; send_pkg ((struct pkg *) &stat, addr); }; /*** *** Packettype: updateinfo ***/ void do_updateinfo (struct pkg_updateinfo *stat, _net_addr * addr) { int i; d_printf ("do_updateinfo (%s,%s)\n", addr->host, addr->port); if (addr->pl_nr != bman.p_servnr && !(GT_MP_PTPM)) { /* the data we have got are not from the server */ d_printf ("do_updateinfo: the data we have got are not from the server\n"); return; } for (i=0;istatus[i]; players[i].net.net_istep = stat->step[i]; } }; void send_updateinfo (_net_addr * addr) { struct pkg_updateinfo stat; int i; stat.h.typ = PKG_updateinfo; stat.h.flags = 0; stat.h.len = HTON16 (sizeof (struct pkg_updateinfo)); for (i=0;ihost, addr->port, addr->pl_nr, chat_pkg->text); chat_addline (chat_pkg->text, -1); }; void send_chat (_net_addr * addr, char *text) { struct pkg_chat chat_pkg; int i; chat_pkg.h.typ = PKG_chat; chat_pkg.h.flags = 0; chat_pkg.h.len = HTON16 (sizeof (struct pkg_chat)); for (i = 0; i < sizeof (chat_pkg.text); i++) chat_pkg.text[i] = 0; strncpy (chat_pkg.text, text, sizeof (struct pkg_chat) - sizeof (struct pkg)); send_pkg ((struct pkg *) &chat_pkg, addr); }; /*** *** Packettype: pkgack ***/ void send_pkgack (_net_addr * addr, unsigned char typ, short int id) { struct pkg_pkgack p_ack; p_ack.h.typ = PKG_pkgack; p_ack.h.flags = 0; p_ack.h.len = HTON16 (sizeof (struct pkg_pkgack)); p_ack.id = HTON16 (id); p_ack.typ = typ; send_pkg ((struct pkg *) &p_ack, addr); }; void do_pkgack (struct pkg_pkgack *p_ack, _net_addr * addr) { d_printf ("do_pkgack (%s:%s)\n", addr->host, addr->port); if (rscache_getpos (addr, p_ack->typ, NTOH16 (p_ack->id)) == -1) return; rscache_del (); }; /*** *** Packettype: dropitems *** send a generated list of drop items ***/ void send_dropitems (_net_addr * addr, int pl_nr, _flyingitem ** fitems, int cnt) { char outdata[BUF_SIZE]; // this should be enough memory for the outgoin data struct pkg_dropitem *dipkg = (struct pkg_dropitem *) outdata; // set the pointer to outdata int i; dipkg->h.typ = PKG_dropitem; dipkg->h.len = HTON16 (sizeof (struct pkg_dropitem) + cnt * sizeof (struct pkgdropitemelemt)); dipkg->h.flags = PKGF_ackreq; dipkg->pl_nr = pl_nr; dipkg->from.x = HTON16 (FTOI16 (players[pl_nr].pos.x)); dipkg->from.y = HTON16 (FTOI16 (players[pl_nr].pos.y)); dipkg->count = cnt; for (i = 0; (i < cnt && fitems[i] != NULL); i++) { dipkg->items[i].x = (int) fitems[i]->to.x; dipkg->items[i].y = (int) fitems[i]->to.y; dipkg->items[i].typ = (int) fitems[i]->type; } send_pkg ((struct pkg *) dipkg, addr); }; void do_dropitems (struct pkg_dropitem *di_pkg, _net_addr * addr) { int i; _pointf from; _point to; d_printf ("do_dropitems from:%d (pl_nr %d, cnt %d)\n", addr->pl_nr, di_pkg->pl_nr, di_pkg->count); if (addr->pl_nr == -1) return; from.x = I16TOF (NTOH16 (di_pkg->from.x)); from.y = I16TOF (NTOH16 (di_pkg->from.y)); for (i = 0; i < di_pkg->count; i++) { to.x = di_pkg->items[i].x; to.y = di_pkg->items[i].y; flitems_additem (from, to, di_pkg->items[i].typ); } }; /*** *** Packettype: special *** moves/bombs... whatever will be send as we use it ***/ void do_special (struct pkg_special *sp_pkg, _net_addr * addr) { d_printf ("do_special (addr %d, pl_nr %d, typ %d)\n", addr->pl_nr, sp_pkg->pl_nr, sp_pkg->typ); if (addr->pl_nr == -1 || sp_pkg->pl_nr == -1 || sp_pkg->pl_nr == bman.p_nr || sp_pkg->pl_nr == bman.p2_nr) return; /* set or use special */ if (sp_pkg->typ < SP_max) { players[sp_pkg->pl_nr].special.type = sp_pkg->typ; bman.last_ex_nr = NTOH32 (sp_pkg->ex_nr); special_use (sp_pkg->pl_nr); } /* cleas special */ else if (sp_pkg->typ == SP_clear) special_clear (sp_pkg->pl_nr); }; void send_special (_net_addr * addr, int p_nr, int typ, int ex_nr) { struct pkg_special sp_dat; sp_dat.h.typ = PKG_special; sp_dat.h.len = HTON16 (sizeof (struct pkg_special)); sp_dat.h.flags = PKGF_ackreq; sp_dat.pl_nr = p_nr; sp_dat.typ = typ; sp_dat.ex_nr = HTON32 (ex_nr); send_pkg ((struct pkg *) &sp_dat, addr); }; /*** *** Packettype: mapinfo ***/ void send_mapinfo (_net_addr * addr) { struct pkg_mapinfo map_pkg; map_pkg.h.typ = PKG_mapinfo; map_pkg.h.len = HTON16 (sizeof (struct pkg_mapinfo)); map_pkg.h.flags = PKGF_ackreq; map_pkg.size_x = map.size.x; map_pkg.size_y = map.size.y; map_pkg.bombs = map.bombs; map_pkg.fire = map.fire; map_pkg.shoes = map.shoes; map_pkg.mixed = map.mixed; map_pkg.death = map.death; map_pkg.sp_trigger = map.sp_trigger; map_pkg.sp_row = map.sp_row; map_pkg.sp_push = map.sp_push; map_pkg.start_bombs = bman.start_bombs; map_pkg.start_range = bman.start_range; sprintf (map_pkg.start_speed, "%6f", bman.start_speed); sprintf (map_pkg.bomb_tickingtime, "%6f", bman.bomb_tickingtime); if (map.random_tileset) map_pkg.tileset[0] = 0; else strcpy (map_pkg.tileset, map.tileset); map_pkg.map_selection = map.map_selection; strcpy (map_pkg.mapname, map.map); d_printf ("send_mapinfo: Tileset: %s\n", map.tileset); send_pkg ((struct pkg *) &map_pkg, addr); }; void do_mapinfo (struct pkg_mapinfo *map_pkg, _net_addr * addr) { d_printf ("do_mapinfo (addr %d) size[%d,%d]\n", addr->pl_nr, map_pkg->size_x, map_pkg->size_y); /* check if the server send this information */ if (addr->pl_nr != bman.p_servnr) return; if (map_pkg->tileset[0] == 0) { map.random_tileset = 1; map.tileset[0] = 0; } else { map.random_tileset = 0; strcpy (map.tileset, map_pkg->tileset); } strcpy (map.map, map_pkg->mapname); map.map_selection = map_pkg->map_selection; map.size.x = map_pkg->size_x; map.size.y = map_pkg->size_y; map.bombs = map_pkg->bombs; map.fire = map_pkg->fire; map.shoes = map_pkg->shoes; map.mixed = map_pkg->mixed; map.death = map_pkg->death; map.sp_trigger = map_pkg->sp_trigger; map.sp_push = map_pkg->sp_push; map.sp_row = map_pkg->sp_row; bman.start_bombs = map_pkg->start_bombs; bman.start_range = map_pkg->start_range; sscanf (map_pkg->start_speed, "%f", &bman.start_speed); sscanf (map_pkg->bomb_tickingtime, "%f", &bman.bomb_tickingtime); }; /*** *** Respawn Date Handling ***/ void send_respawn (_net_addr * addr, int plnr) { struct pkg_respawn r_dat; r_dat.h.typ = PKG_respawn; r_dat.h.len = HTON16 (sizeof (struct pkg_respawn)); r_dat.h.flags = PKGF_ackreq; r_dat.pl_nr = plnr; r_dat.state = players[plnr].state; r_dat.x = players[plnr].pos.x; r_dat.y = players[plnr].pos.y; send_pkg ((struct pkg *) &r_dat, addr); }; void do_respawn (struct pkg_respawn *r_pkg, _net_addr *addr) { d_printf ("do_respawn (addr %d, pl_nr %d, pos %d,%d)\n", addr->pl_nr, r_pkg->pl_nr, r_pkg->x, r_pkg->y); if (addr->pl_nr == -1 || r_pkg->pl_nr == -1) return; /* check if the right player is sending the information */ if (addr->pl_nr != bman.p_servnr && r_pkg->pl_nr != addr->pl_nr) return; if ((r_pkg->state & PSF_respawn) == PSF_respawn) { players[r_pkg->pl_nr].pos.x = r_pkg->x; players[r_pkg->pl_nr].pos.y = r_pkg->y; players[r_pkg->pl_nr].state &= (0xFF - PSF_alife); players[r_pkg->pl_nr].state |= PSF_respawn; players[r_pkg->pl_nr].frame = 0.0f; } else if (r_pkg->state & (PSF_respawn + PSF_alife)) { players[r_pkg->pl_nr].pos.x = r_pkg->x; players[r_pkg->pl_nr].pos.y = r_pkg->y; players[r_pkg->pl_nr].state |= PSF_alife; players[r_pkg->pl_nr].state &= (0xFF - PSF_respawn); } }; /*** *** general packet handling, like check for double recived packets *** network type. Autoreply on PKGF_ackreq and such things. ***/ /* check incoming packet, if we have got the same already if so return != -1 if we haven't got it yet, Add to the incache and return -1 */ int inpkg_check (unsigned char typ, short int id, _net_addr * addr) { int i, pos; /* check if the player is still connected */ if (!PS_IS_used (players[addr->pl_nr].state)) return -1; /* find packet */ for (i = 0, pos = -1; (i < PKG_IN_INDEX_NUM && pos == -1); i++) if (inpkg_index[i].pl_nr == addr->pl_nr && inpkg_index[i].typ == typ && inpkg_index[i].id == id) pos = i; if (pos == -1) { /* add to index */ if (++inpkg_index_pos >= PKG_IN_INDEX_NUM) inpkg_index_pos = 0; inpkg_index[inpkg_index_pos].pl_nr = addr->pl_nr; inpkg_index[inpkg_index_pos].typ = typ; inpkg_index[inpkg_index_pos].id = id; } return pos; }; /* delete all old pkg indexes about a player */ void inpkg_delplayer (int pl_nr) { int i; for (i = 0; i < PKG_IN_INDEX_NUM; i++) if (inpkg_index[i].pl_nr == pl_nr) inpkg_index[i].pl_nr = -1; } /* sends the packet and if PKGF_ackreq is set add packet to the resendcache */ void send_pkg (struct pkg *packet, _net_addr * addr) { /* check if the packet would be send to * an AI_Player, so ignore it. */ if ((addr->pl_nr >= 0 && addr->pl_nr < MAX_PLAYERS) && PS_IS_aiplayer (players[addr->pl_nr].state)) return; /* set the id for the packet and the network flags * the id is needed for the inpkg index to check for * double reached packets */ packet->h.id = HTON16 (pkg_lastid++); if (bman.net_ai_family != PF_INET) packet->h.flags = packet->h.flags | PKGF_ipv6; udp_send (bman.sock, (char *) packet, NTOH16 (packet->h.len), &addr->sAddr, bman.net_ai_family); /* if PKGF_ackreq is set add the packet to the resendcache * so we can resend it if no PKF_ackreq returned for the packet. */ if (packet->h.flags & PKGF_ackreq) { if (rscache_add (addr, packet) == -1) d_printf ("resend_cache overrun.... packet throw away.\n"); } }; /* forward the packet to all who are behind a firewall */ void fwd_pkg (struct pkg *packet, _net_addr * addr) { int pl; if (GT_MP_PTPS) /* clients don't forward anything */ return; if (packet->h.typ >= PKG_field && packet->h.typ < PKG_quit) { for (pl = 0; pl < MAX_PLAYERS; pl++) if ((!PS_IS_aiplayer (players[pl].state)) && PS_IS_netplayer (players[pl].state) && ((players[addr->pl_nr].net.flags & NETF_firewall) == NETF_firewall || (players[pl].net.flags & NETF_firewall) == NETF_firewall) && pl != addr->pl_nr && (players[pl].net.flags & NETF_local2) == 0) send_pkg (packet, &players[pl].net.addr); } else if (packet->h.typ > PKG_quit) d_fatal ("fwd_pkg: not forwarding unknown packet From Player:%d (%s) Typ:%d Len:%d\n", addr->pl_nr, players[addr->pl_nr].name, packet->h.typ, NTOH16 (packet->h.len)); }; /* entry point for all incoming network data. determinate packet type and forward it to all needed functions, like inpkg_check()--> send answer if needed, if we are the server then forward the packet if needed and go into the do_PACKETTYP function */ int do_pkg (struct pkg *packet, _net_addr * addr) { if (((packet->h.flags & PKGF_ipv6) == 0 && bman.net_ai_family != PF_INET) || ((packet->h.flags & PKGF_ipv6) != 0 && bman.net_ai_family == PF_INET)) { d_printf ("do_pkg: packet comes from the wrong network type\n"); return 0; } /* get the addr and set the ping timeout value * check if the packet is from a player in the game and not from someone else * this exception is only for PKG_joingame, PKG_error and PKG_contest */ addr->pl_nr = get_player_nr (addr->host, addr->port); if ((addr->pl_nr < 0 || addr->pl_nr >= MAX_PLAYERS) && packet->h.typ > PKG_contest && PS_IS_netplayer (players[addr->pl_nr].state)) { d_printf ("do_pkg: error addr->pl_nr out of range\n"); return 0; } if (addr->pl_nr >= 0 && addr->pl_nr < MAX_PLAYERS) { players[addr->pl_nr].net.timestamp = timestamp; players[addr->pl_nr].net.pingreq = players[addr->pl_nr].net.pingack + 5; /* test if we have any important packet */ if (packet->h.flags & PKGF_ackreq) { /* we need to send an acknolege so the client * knows we have got this packet and delete * it from the resend cache. */ send_pkgack (addr, packet->h.typ, NTOH16 (packet->h.id)); /* check the packet with the index so we can * ignore packets we already have got * this is important to keep away from * the bomb is dropped twice bug. */ if (inpkg_check (packet->h.typ, NTOH16 (packet->h.id), addr) != -1) { /* we have got this packet already */ d_printf ("do_pkg: double packet ignoring addr->pl_nr=%d\n", addr->pl_nr); if (addr->pl_nr >= 0 && addr->pl_nr < MAX_PLAYERS) players[addr->pl_nr].net.pkgopt.to_2sec++; return 0; } } /* forward packet */ if (GT_MP_PTPM) fwd_pkg (packet, addr); } switch (packet->h.typ) { case (PKG_error): if (do_error ((struct pkg_error *) packet, addr) < 0) return -1; break; case (PKG_playerid): do_playerid ((struct pkg_playerid *) packet, addr); break; case (PKG_servermode): do_servermode ((struct pkg_servermode *) packet, addr); break; case (PKG_field): do_field ((struct pkg_field *) packet, addr); break; case (PKG_contest): do_contest ((struct pkg_contest *) packet, addr); break; case (PKG_pingreq): do_ping ((struct pkg_ping *) packet, addr); break; case (PKG_pingack): do_ping ((struct pkg_ping *) packet, addr); break; case (PKG_bombdata): do_bombdata ((struct pkg_bombdata *) packet, addr); break; case (PKG_playerdata): do_playerdata ((struct pkg_playerdata *) packet, addr); break; case (PKG_quit): do_quit ((struct pkg_quit *) packet, addr); break; case (PKG_getfield): do_getfield ((struct pkg_getfield *) packet, addr); break; case (PKG_getplayerdata): do_getplayerdata ((struct pkg_getplayerdata *) packet, addr); break; case (PKG_fieldline): do_fieldline ((struct pkg_fieldline *) packet, addr); break; case (PKG_playerstatus): do_playerstatus ((struct pkg_playerstatus *) packet, addr); break; case (PKG_pkgack): do_pkgack ((struct pkg_pkgack *) packet, addr); break; case (PKG_chat): do_chat ((struct pkg_chat *) packet, addr); break; case (PKG_playermove): do_playermove ((struct pkg_playermove *) packet, addr); break; case (PKG_ill): do_ill ((struct pkg_ill *) packet, addr); break; case (PKG_special): do_special ((struct pkg_special *) packet, addr); break; case (PKG_mapinfo): do_mapinfo ((struct pkg_mapinfo *) packet, addr); break; case (PKG_tunneldata): do_tunneldata ((struct pkg_tunneldata *) packet, addr); break; case (PKG_joingame): do_joingame ((struct pkg_joingame *) packet, addr); break; case (PKG_dropitem): do_dropitems ((struct pkg_dropitem *) packet, addr); break; case (PKG_respawn): do_respawn ((struct pkg_respawn *) packet, addr); break; case (PKG_updateinfo): do_updateinfo ((struct pkg_updateinfo *) packet, addr); break; default: send_error (addr, "BomberClone: unknown data packet"); break; } return 0; };