/* network commands and data */ #include "basic.h" #include "bomberclone.h" #include "network.h" #include "gamesrv.h" #include "packets.h" #include "chat.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; int get_player_nr (char *host, char *port) { int i, res; for (i = 0, res = -1; (i < MAX_PLAYERS && res == -1); i++) { if (bman.players[i].net.addr.host[0] != 0) if ((strcmp (bman.players[i].net.addr.host, host) == 0) && (strcmp (bman.players[i].net.addr.port, port) == 0)) res = i; } return res; } 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 = 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 : '%s'\n", data->text); menu_displaymessage ("Network Error", data->text); if (data->nr == 1) return -1; else return 0; }; /* update the playerinformations in the game */ void do_playerid (struct pkg_playerid *p_id, _net_addr * addr) { _player *pl; int i, j, vma, vmi, vsu; char text[255]; sscanf (VERSION, "%d.%d.%d", &vma, &vmi, &vsu); if (p_id->ver_sub != vsu || p_id->ver_major != vma || p_id->ver_minor != vmi) { sprintf (text, "Version Error - Host/Server Version: %s", VERSION); send_error (addr, text); return; } 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); /* As Server/Master Only change settings, or do ignore them if we are not in GS_wait */ if (((GT_MP_PTPM && (bman.state == GS_wait && addr->pl_nr != -1)) || // PTPM change setting (GT_MP_PTPS && addr->pl_nr == 0)) && p_id->pl_nr >= 0 && p_id->pl_nr < MAX_PLAYERS) { // PTPS and information send by PTPM pl = &bman.players[p_id->pl_nr]; 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); player_set_gfx (pl, p_id->gfx_nr); strncpy (pl->name, p_id->name, LEN_PLAYERNAME); pl->net.timestamp = timestamp; pl->net.pingreq = pl->net.pingack + 5; 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); } if (GT_MP_PTPS) { pl->points = p_id->points; pl->wins = p_id->wins; } } /* add player into the list if there is something free */ else if ((addr->pl_nr == -1 || p_id->pl_nr == -1) && GS_WAITRUNNING && GT_MP_PTPM) { /* find free player slot */ if (addr->pl_nr == -1) for (i = 0; (i < MAX_PLAYERS && PS_IS_used (bman.players[i].state)); i++); else i = addr->pl_nr; if ((i < MAX_PLAYERS) && (i < bman.maxplayer)) { /* free in_pl slot ... fill in data */ pl = &bman.players[i]; pl->state = PSF_used + PSF_net; if (strncmp (pl->name, p_id->name, LEN_PLAYERNAME) == 0) d_printf ("***** Player ReJoined : Nr:[%d] Name:%10s\n", i, p_id->name); else { d_printf ("***** Player Added : Nr:[%d] Name:%10s\n", i, p_id->name); pl->points = 0; pl->wins = 0; } strncpy (pl->name, p_id->name, LEN_PLAYERNAME); player_set_gfx (pl, p_id->gfx_nr); /* 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); pl->net.addr.pl_nr = i; bman.players_nr_s++; /* send to the new client the servermode and the complete playerlist */ send_servermode (addr, i); for (j = 0; j < MAX_PLAYERS; j++) if (bman.players[j].net.addr.host[0] != 0 || bman.players[j].name[0] != 0) send_playerid (addr, bman.players[j].name, bman.players[j].net.addr.host, bman.players[j].net.addr.port, j, bman.players[j].gfx_nr); addr->pl_nr = i; for (j = 0, i = 0; i < bman.maxplayer; i++) if (PS_IS_used (bman.players[i].state)) j++; bman.updatestatusbar=1; if (bman.notifygamemaster) gamesrv_sendmode (bman.maxplayer, j); } else if (GS_WAITRUNNING) { send_error (addr, "No Free Playerslot found\n"); return; } else if (!GS_WAITRUNNING) { send_error (addr, "Game is in the wrong mode.\n"); return; } } /* Send all connected players the new PlayerID */ if (GS_WAITRUNNING && addr->pl_nr >= 0 && addr->pl_nr < MAX_PLAYERS) net_change_playerid (addr->pl_nr, (GT_MP_PTPM)); d_playerdetail ("*** PLAYER List ***"); }; void send_playerid (_net_addr * addr, char *name, char *pladdr, char *plport, int pl_nr, int gfx_nr) { struct pkg_playerid p_id; int vmi, vma, vsu; d_printf ("send_playerid SendTo: %s:%s (Name:%16s p_nr:%d)\n", addr->host, addr->port, name, pl_nr); sscanf (VERSION, "%d.%d.%d", &vma, &vmi, &vsu); p_id.h.typ = PKG_playerid; p_id.h.flags = PKGF_ackreq; p_id.h.len = sizeof (struct pkg_playerid); p_id.ver_sub = vsu; p_id.ver_major = vma; p_id.ver_minor = vmi; strncpy (p_id.name, name, LEN_PLAYERNAME); 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.gfx_nr = gfx_nr; if (pl_nr != -1) { p_id.points = bman.players[pl_nr].points; p_id.wins = bman.players[pl_nr].wins; p_id.state = bman.players[pl_nr].state; } else { p_id.points = 0; p_id.wins = 0; p_id.state = 0; } send_pkg ((struct pkg *) &p_id, addr); }; 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 (s_mod->pl_nr >= 0 && s_mod->pl_nr < MAX_PLAYERS) { bman.p_nr = s_mod->pl_nr; bman.players[bman.p_nr].state &= (0xFF - PSF_net); strncpy (bman.players[s_mod->pl_nr].name, bman.playername, LEN_PLAYERNAME); } if (s_mod->type == GT_multi) bman.gametype = GT_multi; else bman.gametype = GT_single; bman.state = s_mod->state; if (s_mod->multitype == MT_ptpm) bman.multitype = MT_ptps; bman.players_nr_s = s_mod->players; bman.lastwinner = s_mod->last_winner; if (GT_MP_PTPS) { bman.fieldsize.x = s_mod->fieldsize_x; bman.fieldsize.y = s_mod->fieldsize_y; } strncpy (gfx.tileset, s_mod->tileset, LEN_TILESETNAME); bman.updatestatusbar = 1; }; void send_servermode (_net_addr * addr, int pl_nr) { struct pkg_servermode s_mod; d_printf ("Send ServerMode\n"); s_mod.h.typ = PKG_servermode; s_mod.h.len = sizeof (struct pkg_servermode); s_mod.h.flags = PKGF_ackreq; s_mod.type = bman.gametype; s_mod.state = bman.state; s_mod.multitype = bman.multitype; s_mod.players = bman.players_nr_s; s_mod.maxplayer = bman.maxplayer; s_mod.pl_nr = pl_nr; s_mod.last_winner = bman.lastwinner; s_mod.fieldsize_x = bman.fieldsize.x; s_mod.fieldsize_y = bman.fieldsize.y; strncpy (s_mod.tileset, gfx.tileset, LEN_TILESETNAME); send_pkg ((struct pkg *) &s_mod, addr); }; void send_field (_net_addr * addr, int x, int y, _field * field) { struct pkg_field f_dat; d_printf ("send_field [%d,%d]\n", x, y); f_dat.h.typ = PKG_field; f_dat.h.len = sizeof (struct pkg_field); f_dat.h.flags = PKGF_ackreq; f_dat.x = x; f_dat.y = y; if (x < 0 || x >= bman.fieldsize.x || y < 0 || y >= bman.fieldsize.y) return; memcpy (&f_dat.field, &bman.field[x][y], sizeof (_field)); send_pkg ((struct pkg *) &f_dat, addr); }; void do_field (struct pkg_field *f_dat, _net_addr * addr) { if (addr->pl_nr == -1) return; if (f_dat->x < bman.fieldsize.x && f_dat->y < bman.fieldsize.y) { memcpy (&bman.field[f_dat->x][f_dat->y], &f_dat->field, sizeof (_field)); } if (bman.state == GS_running) draw_stone (f_dat->x, f_dat->y); if (f_dat->field.ex_nr > bman.last_ex_nr) bman.last_ex_nr = f_dat->field.ex_nr; d_printf ("do_field (%d,%d) ex_nr = %d, special = %d, type = %d\n", f_dat->x, f_dat->y, f_dat->field.ex_nr, f_dat->field.special, f_dat->field.type); }; 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 */ bman.players[addr->pl_nr].net.pingack = p_dat->data; else /* send the answer */ send_ping (addr, 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, bman.players[addr->pl_nr].net.pingreq, bman.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 = sizeof (struct pkg_ping); p_dat.h.flags = 0; if (typ == PKG_pingack) { p_dat.h.typ = typ; p_dat.data = data; send_pkg ((struct pkg *) &p_dat, addr); } else if (typ == PKG_pingreq) { p_dat.h.typ = typ; p_dat.data = 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, bman.players[addr->pl_nr].net.pingreq, bman.players[addr->pl_nr].net.pingack); bman.players[addr->pl_nr].net.timestamp = timestamp; /* we need to set it here, so we can check for the timeout again */ }; 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 = 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 = pl->pos.x; p_dat.pos.y = 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 = pl->wins; p_dat.points = pl->points; p_dat.dead_by = pl->dead_by; p_dat.frame = pl->frame; p_dat.p_nr = p_nr; 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 = &bman.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 = p_dat->points; pl->dead_by = p_dat->dead_by; } else if (bman.state != GS_running || bman.p_nr != p_dat->p_nr) { pl->pos.x = p_dat->pos.x; pl->pos.y = p_dat->pos.y; pl->dead_by = p_dat->dead_by; pl->points = p_dat->points; pl->d = p_dat->d; pl->bombs_n = p_dat->bombs_n; pl->range = p_dat->range; pl->frame = p_dat->frame; pl->state = p_dat->state; } 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) { bman.players[p_dat->dead_by].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 (bman.state == GS_update && bman.players[bman.p_nr].net.net_istep == 1) bman.players[bman.p_nr].net.net_status = p_dat->p_nr; } 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 = sizeof (struct pkg_playermove); p_dat.h.flags = 0; p_dat.pos.x = pl->pos.x; p_dat.pos.y = pl->pos.y; p_dat.m = pl->m; p_dat.d = pl->d; p_dat.p_nr = p_nr; p_dat.speed = pl->speed; send_pkg ((struct pkg *) &p_dat, addr); }; void do_ill (struct pkg_ill *ill, _net_addr * addr) { int i; 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++) bman.players[ill->pl_nr].ill[i].to = ill->to[i]; }; 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 = sizeof (struct pkg_ill); ill.h.flags = PKGF_ackreq; ill.pl_nr = p_nr; for (i = 0; i < PI_max; i++) ill.to[i] = pl->ill[i].to; send_pkg ((struct pkg *) &ill, 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; /* check if the right player is sending the information */ pl = &bman.players[p_dat->p_nr]; if (addr->pl_nr != 0 && addr->pl_nr != p_dat->p_nr) return; pl->m = p_dat->m; pl->d = p_dat->d; pl->speed = p_dat->speed; pl->pos.x = p_dat->pos.x; pl->pos.y = p_dat->pos.y; } 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 [%d,%d] Player: %d Bomb: %d, ex_nr:%d\n", b_dat->x, b_dat->y, b_dat->p_nr, b_dat->b_nr, b_dat->ex_nr); bomb = &bman.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 != b_dat->x || bomb->pos.y != b_dat->y) && bomb->state == BS_exploding && b_dat->state != BS_exploding) d_printf ("do_bombdata WARNING : bomb explosion haven't finished\n"); bomb->pos.x = b_dat->x; bomb->pos.y = b_dat->y; if (bomb->state != BS_ticking) bomb->to = b_dat->to; else bman.bfield[bomb->pos.x][bomb->pos.y] = 1; // keep the bfield up to date bomb->r = b_dat->r; bomb->ex_nr = b_dat->ex_nr; bomb->state = b_dat->state; if (bomb->state == BS_exploding) bomb_explode (b_dat->p_nr, b_dat->b_nr,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 = sizeof (struct pkg_bombdata); b_dat.x = bomb->pos.x; b_dat.y = bomb->pos.y; b_dat.to = bomb->to; b_dat.r = bomb->r; b_dat.ex_nr = bomb->ex_nr; b_dat.state = bomb->state; b_dat.b_nr = b; b_dat.p_nr = p; b_dat.h.flags = PKGF_ackreq; send_pkg ((struct pkg *) &b_dat, addr); }; void send_quit (_net_addr * addr, char *plhost, char *plport) { struct pkg_quit q_dat; d_printf ("send_quit (%s:%s) plhost (%s:%s)\n", addr->host, addr->port, plhost, plport); q_dat.h.typ = PKG_quit; q_dat.h.flags = 0; q_dat.h.len = sizeof (struct pkg_quit); if (plhost == NULL) { q_dat.host[0] = 0; q_dat.port[0] = 0; } else { strncpy (q_dat.host, plhost, LEN_SERVERNAME); strncpy (q_dat.port, plport, LEN_PORT); } 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, addr->pl_nr); if (addr->pl_nr == -1) return; if (q_dat->host[0] == 0) /* the player who send this quit */ net_delplayer (addr->pl_nr); else { /* delete the player with the giving address */ int pl_nr = get_player_nr (q_dat->host, q_dat->port); if (pl_nr == -1) return; net_delplayer (pl_nr); } }; void send_getfield (_net_addr * addr, int line) { struct pkg_getfield gf_dat; gf_dat.h.typ = PKG_getfield; gf_dat.h.len = 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 > 0 && addr->pl_nr < MAX_PLAYERS) { bman.players[addr->pl_nr].net.net_status = gf_dat->line; bman.players[addr->pl_nr].net.net_istep = 2; } } send_fieldline (addr, gf_dat->line); }; 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 = 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] = bman.field[i][line].type; f_dat.special[i] = bman.field[i][line].special; bman.field[i][line].frame = 0; bman.field[i][line].frameto = 0; bman.field[i][line].ex_nr = 0; for (j = 0; j < 4; j++) bman.field[i][line].ex[j].frame = bman.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 != 0) { /* 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 (bman.state == GS_update && bman.players[bman.p_nr].net.net_istep == 2) bman.players[bman.p_nr].net.net_status = f_dat->line; for (i = 0; i < MAX_FIELDSIZE_X; i++) { bman.field[i][f_dat->line].type = f_dat->type[i]; bman.field[i][f_dat->line].special = f_dat->special[i]; for (d = 0; d < 4; d++) bman.field[i][f_dat->line].ex[d].frame = bman.field[i][f_dat->line].ex[d].count = 0; } }; void send_getplayerdata (_net_addr * addr, int pl) { struct pkg_getplayerdata gp_dat; gp_dat.h.typ = PKG_getplayerdata; gp_dat.h.len = 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 > 0 && addr->pl_nr < MAX_PLAYERS) { bman.players[addr->pl_nr].net.net_status = gp_dat->pl_nr; bman.players[addr->pl_nr].net.net_istep = 1; } } send_playerdata (addr, gp_dat->pl_nr, &bman.players[gp_dat->pl_nr]); }; void do_playerstatus (struct pkg_playerstatus *stat, _net_addr * addr) { int i; d_printf ("do_playerstatus (%s,%s)\n", addr->host, addr->port); if (addr->pl_nr != 0 && !(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 line number is wrong */ d_printf ("do_playerstatus: playernumber not correct\n"); return; } bman.players[addr->pl_nr].net.net_status = stat->status; bman.players[addr->pl_nr].net.net_istep = stat->net_istep; if (GT_MP_PTPM) for (i = 0; i < MAX_PLAYERS; i++) if (bman.players[i].net.addr.host[0] != 0) send_playerstatus (&bman.players[i].net.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 = sizeof (struct pkg_playerstatus); stat.pl_nr = pl_nr; stat.net_istep = net_istep; stat.status = status; send_pkg ((struct pkg *) &stat, addr); }; void do_chat (struct pkg_chat *chat_pkg, _net_addr * addr) { chat_addline (chat_pkg->text); if (GT_MP_PTPM && bman.notifygamemaster) /* send notification the the gamemaster */ gamesrv_sendchat (chat_pkg->text); }; 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 = 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); }; 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 = sizeof (struct pkg_pkgack); p_ack.id = 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, p_ack->id) == -1) return; rscache_del (); }; /* Player 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) return; if (sp_pkg->pl_nr == -1) return; /* check if the right player is sending the information */ if (addr->pl_nr != 0 && addr->pl_nr != sp_pkg->pl_nr) return; bman.players[sp_pkg->pl_nr].special = sp_pkg->typ; bman.last_ex_nr = sp_pkg->ex_nr; special_use (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 = sizeof (struct pkg_special); sp_dat.h.flags = PKGF_ackreq; sp_dat.pl_nr = p_nr; sp_dat.typ = typ; sp_dat.ex_nr = ex_nr; send_pkg ((struct pkg *) &sp_dat, addr); }; void do_bcmservchat (struct pkg_bcmservchat *packet, _net_addr * addr) { packet->data[127] = 0; if (strstr (packet->data,"BC:BC:") == packet->data) return; // ignore packet chat_addline (packet->data); net_send_chat (packet->data, 0); }; int inpkg_check (unsigned char typ, short int id, _net_addr * addr) { int i, pos; /* 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) { /* packet unknown ... 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; }; void send_pkg (struct pkg *packet, _net_addr * addr) { packet->h.id = pkg_lastid++; if (bman.net_ai_family != PF_INET) packet->h.flags = packet->h.flags | PKGF_ipv6; udp_send (bman.sock, (char *) packet, packet->h.len, &addr->sAddr, bman.net_ai_family); /* test if we have any important packet if so put it in the resend_cache */ if (packet->h.flags & PKGF_ackreq) { if (rscache_add (addr, packet) == -1) d_printf ("resend_cache overrun.... packet throw away.\n"); } }; 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)) && packet->h.typ != PKG_bcmservchat) { d_printf ("-----packet comes from the wrong network type\n"); return 0; } /* get the addr and set the ping timeout value */ addr->pl_nr = get_player_nr (addr->host, addr->port); bman.players[addr->pl_nr].net.timestamp = timestamp; bman.players[addr->pl_nr].net.pingreq = bman.players[addr->pl_nr].net.pingack + 5; /* test if we have any important packet */ if (packet->h.flags & PKGF_ackreq && packet->h.typ != PKG_bcmservchat) send_pkgack (addr, packet->h.typ, packet->h.id); /* check the packet with the index */ if (packet->h.typ != PKG_bcmservchat && inpkg_check (packet->h.typ, packet->h.id, addr) != -1) { /* we have got this packet already */ d_printf ("-----packet ignored\n"); if (addr->pl_nr >= 0 && addr->pl_nr < MAX_PLAYERS) bman.players[addr->pl_nr].net.pkgopt.to_2sec++; return 0; } /* check if the incoming packet have the right size */ if (packet->h.typ == PKG_servermode && packet->h.len != sizeof (struct pkg_servermode)) send_error (addr, "pkg_servermode: packetsize incorrect."); 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_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_bcmservchat): do_bcmservchat ((struct pkg_bcmservchat *) 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; default: send_error (addr, "BomberClone: unknown data packet"); break; } return 0; };