mirror of
https://github.com/gamedig/node-gamedig.git
synced 2024-11-18 17:50:37 +01:00
277 lines
6.7 KiB
Text
277 lines
6.7 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;
|
||
|
}
|
||
|
|
||
|
|