node-gamedig/reference/bfris/qstat.txt
2014-10-29 02:02:03 -05:00

276 lines
6.4 KiB
Text

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;
}