LICENSE: The Artistic License 2.0 /* * qstat.h * by Steve Jankowski * steve@qstat.org * http://www.qstat.org * * Copyright 1996,1997,1998,1999,2000,2001,2002 by Steve Jankowski */ { /* BFRIS */ BFRIS_SERVER, /* id */ "BFS", /* type_prefix */ "bfs", /* type_string */ "-bfs", /* type_option */ "BFRIS", /* game_name */ 0, /* master */ BFRIS_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT, /* flags */ "Rules", /* game_rule */ "BFRIS", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_bfris_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_bfris_player_info,/* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_bfris_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_bfris_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_bfris_packet, /* packet_func */ }, /* postions of map name, player name (in player substring), zero-based */ #define BFRIS_MAP_POS 18 #define BFRIS_PNAME_POS 11 query_status_t deal_with_bfris_packet(struct qserver *server, char *rawpkt, int pktlen) { int i, player_data_pos, nplayers; SavedData *sdata; unsigned char *saved_data; int saved_data_size; debug( 2, "deal_with_bfris_packet %p, %d", server, pktlen ); server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); /* add to the data previously saved */ sdata = &server->saved_data; if (!sdata->data) { sdata->data = (char*)malloc(pktlen); } else { sdata->data = (char*)realloc(sdata->data, sdata->datalen + pktlen); } memcpy(sdata->data + sdata->datalen, rawpkt, pktlen); sdata->datalen += pktlen; saved_data = (unsigned char*)sdata->data; saved_data_size = sdata->datalen; /* after we get the server portion of the data, server->game != NULL */ if (!server->game) { /* server data goes up to map name */ if (sdata->datalen <= BFRIS_MAP_POS) { return INPROGRESS; } /* see if map name is complete */ player_data_pos = 0; for (i = BFRIS_MAP_POS; i < saved_data_size; i++) { if (saved_data[i] == '\0') { player_data_pos = i + 1; /* data must extend beyond map name */ if (saved_data_size <= player_data_pos) { return INPROGRESS; } break; } } /* did we find beginning of player data? */ if (!player_data_pos) { return INPROGRESS; } /* now we can go ahead and fill in server data */ server->map_name = strdup((char*)saved_data + BFRIS_MAP_POS); server->max_players = saved_data[12]; server->protocol_version = saved_data[11]; /* save game type */ switch (saved_data[13] &15) { case 0: server->game = "FFA"; break; case 5: server->game = "Rover"; break; case 6: server->game = "Occupation"; break; case 7: server->game = "SPAAL"; break; case 8: server->game = "CTF"; break; default: server->game = "unknown"; break; } server->flags |= FLAG_DO_NOT_FREE_GAME; add_rule(server, server->type->game_rule, server->game, NO_FLAGS); if (get_server_rules) { char buf[24]; /* server revision */ sprintf(buf, "%d", (unsigned int)saved_data[11]); add_rule(server, "Revision", buf, NO_FLAGS); /* latency */ sprintf(buf, "%d", (unsigned int)saved_data[10]); add_rule(server, "Latency", buf, NO_FLAGS); /* player allocation */ add_rule(server, "Allocation", saved_data[13] &16 ? "Automatic" : "Manual", NO_FLAGS); } } /* If we got this far, we know the data saved goes at least to the start of the player information, and that the server data is taken care of. */ /* start of player data */ player_data_pos = BFRIS_MAP_POS + strlen((char*)saved_data + BFRIS_MAP_POS) + 1; /* ensure all player data have arrived */ nplayers = 0; while (saved_data[player_data_pos] != '\0') { player_data_pos += BFRIS_PNAME_POS; /* does player data extend to player name? */ if (saved_data_size <= player_data_pos + 1) { return INPROGRESS; } /* does player data extend to end of player name? */ for (i = 0; player_data_pos + i < saved_data_size; i++) { if (saved_data_size == player_data_pos + i + 1) { return INPROGRESS; } if (saved_data[player_data_pos + i] == '\0') { player_data_pos += i + 1; nplayers++; break; } } } /* all player data are complete */ server->num_players = nplayers; if (get_player_info) { /* start of player data */ player_data_pos = BFRIS_MAP_POS + strlen((char*)saved_data + BFRIS_MAP_POS) + 1; for (i = 0; i < nplayers; i++) { struct player *player; player = add_player(server, saved_data[player_data_pos]); player->ship = saved_data[player_data_pos + 1]; player->ping = saved_data[player_data_pos + 2]; player->frags = saved_data[player_data_pos + 3]; player->team = saved_data[player_data_pos + 4]; switch (player->team) { case 0: player->team_name = "silver"; break; case 1: player->team_name = "red"; break; case 2: player->team_name = "blue"; break; case 3: player->team_name = "green"; break; case 4: player->team_name = "purple"; break; case 5: player->team_name = "yellow"; break; case 6: player->team_name = "cyan"; break; default: player->team_name = "unknown"; break; } player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM; player->room = saved_data[player_data_pos + 5]; /* score is little-endian integer */ player->score = saved_data[player_data_pos + 7] + (saved_data[player_data_pos + 8] << 8) + (saved_data[player_data_pos + 9] << 16) + (saved_data[player_data_pos + 10] << 24); /* for archs with > 4-byte int */ if (player->score &0x80000000) { player->score = - (~(player->score)) - 1; } player_data_pos += BFRIS_PNAME_POS; player->name = strdup((char*)saved_data + player_data_pos); player_data_pos += strlen(player->name) + 1; } } server->server_name = BFRIS_SERVER_NAME; return DONE_FORCE; }