2014-10-29 08:02:03 +01:00
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* for some reason Descent3 uses a different request for pxo/non-pxo games. blah. */
|
|
|
|
unsigned char descent3_pxoinfoquery[] = {
|
|
|
|
0x01, /* "internal descent3 routing" */
|
|
|
|
0x29, /* request server info? (pxo listed servers) */
|
|
|
|
0x0b, 0x00, /* packet length (- routing byte) */
|
|
|
|
0x1b, 0x2f, 0xf4, 0x41, 0x09, 0x00, 0x00, 0x00 /* unknown */
|
|
|
|
};
|
|
|
|
unsigned char descent3_tcpipinfoquery[] = {
|
|
|
|
0x01, /* "internal descent3 routing" */
|
|
|
|
0x1e, /* request server info? (tcpip only servers) */
|
|
|
|
0x0b, 0x00, /* packet length (- routing byte) */
|
|
|
|
0x1b, 0x2f, 0xf4, 0x41, 0x09, 0x00, 0x00, 0x00 /* unknown */
|
|
|
|
};
|
|
|
|
/* http://ml.warpcore.org/d3dl/200101/msg00001.html
|
|
|
|
* http://ml.warpcore.org/d3dl/200101/msg00004.html */
|
|
|
|
unsigned char descent3_playerquery[] = {
|
|
|
|
0x01, /* "internal descent3 routing" */
|
|
|
|
0x72, /* MP_REQUEST_PLAYERLIST */
|
|
|
|
0x03, 0x00 /* packet length (- routing byte) */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
/* DESCENT3 PROTOCOL */
|
|
|
|
DESCENT3_SERVER, /* id */
|
|
|
|
"D3S", /* type_prefix */
|
|
|
|
"d3s", /* type_string */
|
|
|
|
"-d3s", /* type_option */
|
|
|
|
"Descent3", /* game_name */
|
|
|
|
0, /* master */
|
|
|
|
DESCENT3_DEFAULT_PORT, /* default_port */
|
|
|
|
0, /* port_offset */
|
|
|
|
0, /* flags */
|
|
|
|
"gametype", /* game_rule */
|
|
|
|
"DESCENT3", /* template_var */
|
|
|
|
(char*) &descent3_tcpipinfoquery, /* status_packet */
|
|
|
|
sizeof( descent3_tcpipinfoquery), /* status_len */
|
|
|
|
(char*) &descent3_playerquery, /* player_packet */
|
|
|
|
sizeof( descent3_playerquery), /* player_len */
|
|
|
|
NULL, /* rule_packet */
|
|
|
|
0, /* rule_len */
|
|
|
|
NULL, /* master_packet */
|
|
|
|
0, /* master_len */
|
|
|
|
NULL, /* master_protocol */
|
|
|
|
NULL, /* master_query */
|
|
|
|
display_descent3_player_info, /* display_player_func */
|
|
|
|
display_server_rules, /* display_rule_func */
|
|
|
|
raw_display_descent3_player_info, /* display_raw_player_func */
|
|
|
|
raw_display_server_rules, /* display_raw_rule_func */
|
|
|
|
xml_display_descent3_player_info, /* display_xml_player_func */
|
|
|
|
xml_display_server_rules, /* display_xml_rule_func */
|
|
|
|
send_gps_request_packet, /* status_query_func */
|
|
|
|
NULL, /* rule_query_func */
|
|
|
|
NULL, /* player_query_func */
|
|
|
|
deal_with_descent3_packet, /* packet_func */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
/* DESCENT3 PROTOCOL */
|
|
|
|
DESCENT3_PXO_SERVER, /* id */
|
|
|
|
"D3P", /* type_prefix */
|
|
|
|
"d3p", /* type_string */
|
|
|
|
"-d3p", /* type_option */
|
|
|
|
"Descent3 PXO protocol", /* game_name */
|
|
|
|
0, /* master */
|
|
|
|
DESCENT3_DEFAULT_PORT, /* default_port */
|
|
|
|
0, /* port_offset */
|
|
|
|
0, /* flags */
|
|
|
|
"gametype", /* game_rule */
|
|
|
|
"DESCENT3", /* template_var */
|
|
|
|
(char*) &descent3_pxoinfoquery, /* status_packet */
|
|
|
|
sizeof( descent3_pxoinfoquery), /* status_len */
|
|
|
|
(char*) &descent3_playerquery, /* player_packet */
|
|
|
|
sizeof( descent3_playerquery), /* player_len */
|
|
|
|
NULL, /* rule_packet */
|
|
|
|
0, /* rule_len */
|
|
|
|
NULL, /* master_packet */
|
|
|
|
0, /* master_len */
|
|
|
|
NULL, /* master_protocol */
|
|
|
|
NULL, /* master_query */
|
|
|
|
display_descent3_player_info, /* display_player_func */
|
|
|
|
display_server_rules, /* display_rule_func */
|
|
|
|
raw_display_descent3_player_info, /* display_raw_player_func */
|
|
|
|
raw_display_server_rules, /* display_raw_rule_func */
|
|
|
|
xml_display_descent3_player_info, /* display_xml_player_func */
|
|
|
|
xml_display_server_rules, /* display_xml_rule_func */
|
|
|
|
send_gps_request_packet, /* status_query_func */
|
|
|
|
NULL, /* rule_query_func */
|
|
|
|
NULL, /* player_query_func */
|
|
|
|
deal_with_descent3_packet, /* packet_func */
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
query_status_t deal_with_descent3_packet(struct qserver *server, char *rawpkt, int pktlen)
|
|
|
|
{
|
|
|
|
char *pkt;
|
|
|
|
char buf[24];
|
|
|
|
|
|
|
|
debug( 2, "deal_with_descent3_packet %p, %d", server, pktlen );
|
|
|
|
|
|
|
|
if (server->server_name == NULL)
|
|
|
|
{
|
|
|
|
server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pktlen < 4)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "short descent3 packet\n");
|
|
|
|
print_packet(server, rawpkt, pktlen);
|
|
|
|
return PKT_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 'info' response */
|
|
|
|
if (rawpkt[1] == 0x1f)
|
|
|
|
{
|
|
|
|
if (server->server_name != NULL)
|
|
|
|
{
|
|
|
|
return PKT_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pkt = &rawpkt[0x15];
|
|
|
|
server->server_name = strdup(pkt);
|
|
|
|
pkt += strlen(pkt) + 2;
|
|
|
|
server->map_name = strdup(pkt); /* mission name (blah.mn3) */
|
|
|
|
pkt += strlen(pkt) + 2;
|
|
|
|
add_rule(server, "level_name", pkt, NO_FLAGS);
|
|
|
|
pkt += strlen(pkt) + 2;
|
|
|
|
add_rule(server, "gametype", pkt, NO_FLAGS);
|
|
|
|
pkt += strlen(pkt) + 1;
|
|
|
|
|
|
|
|
sprintf(buf, "%hu", swap_short_from_little(pkt));
|
|
|
|
add_rule(server, "level_num", buf, NO_FLAGS);
|
|
|
|
pkt += 2;
|
|
|
|
server->num_players = swap_short_from_little(pkt);
|
|
|
|
pkt += 2;
|
|
|
|
server->max_players = swap_short_from_little(pkt);
|
|
|
|
pkt += 2;
|
|
|
|
|
|
|
|
/* unknown/undecoded fields.. stuff like permissible, banned items/ships, etc */
|
|
|
|
add_uchar_rule(server, "u0", pkt[0]);
|
|
|
|
add_uchar_rule(server, "u1", pkt[1]);
|
|
|
|
add_uchar_rule(server, "u2", pkt[2]);
|
|
|
|
add_uchar_rule(server, "u3", pkt[3]);
|
|
|
|
add_uchar_rule(server, "u4", pkt[4]);
|
|
|
|
add_uchar_rule(server, "u5", pkt[5]);
|
|
|
|
add_uchar_rule(server, "u6", pkt[6]);
|
|
|
|
add_uchar_rule(server, "u7", pkt[7]);
|
|
|
|
add_uchar_rule(server, "u8", pkt[8]);
|
|
|
|
|
|
|
|
add_uchar_rule(server, "randpowerup", (unsigned char)!(pkt[4] &1)); /*
|
|
|
|
randomize powerup spawn */
|
|
|
|
add_uchar_rule(server, "acccollisions", (unsigned char)((pkt[5] &4) > 0));
|
|
|
|
/* accurate collision detection */
|
|
|
|
add_uchar_rule(server, "brightships", (unsigned char)((pkt[5] &16) > 0));
|
|
|
|
/* bright player ships */
|
|
|
|
add_uchar_rule(server, "mouselook", (unsigned char)((pkt[6] &1) > 0)); /*
|
|
|
|
mouselook enabled */
|
|
|
|
sprintf(buf, "%s%s", (pkt[4] &16) ? "PP" : "CS", (pkt[6] &1) ? "-ML" : "");
|
|
|
|
add_rule(server, "servertype", buf, NO_FLAGS);
|
|
|
|
|
|
|
|
sprintf(buf, "%hhu", pkt[9]);
|
|
|
|
add_rule(server, "difficulty", buf, NO_FLAGS);
|
|
|
|
|
|
|
|
/* unknown/undecoded fields after known flags removed */
|
|
|
|
add_uchar_rule(server, "x4", (unsigned char)(pkt[4] &~(1+16)));
|
|
|
|
add_uchar_rule(server, "x5", (unsigned char)(pkt[5] &~(4+16)));
|
|
|
|
add_uchar_rule(server, "x6", (unsigned char)(pkt[6] &~1));
|
|
|
|
|
|
|
|
if (get_player_info && server->num_players)
|
|
|
|
{
|
|
|
|
server->next_player_info = 0;
|
|
|
|
send_player_request_packet(server);
|
|
|
|
return INPROGRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* MP_PLAYERLIST_DATA */
|
|
|
|
else if (rawpkt[1] == 0x73)
|
|
|
|
{
|
|
|
|
struct player *player;
|
|
|
|
struct player **last_player = &server->players;
|
|
|
|
|
|
|
|
if (server->players != NULL)
|
|
|
|
{
|
|
|
|
return PKT_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
pkt = &rawpkt[0x4];
|
|
|
|
while (*pkt)
|
|
|
|
{
|
|
|
|
player = (struct player*)calloc(1, sizeof(struct player));
|
|
|
|
player->name = strdup(pkt);
|
|
|
|
pkt += strlen(pkt) + 1;
|
|
|
|
*last_player = player;
|
|
|
|
last_player = &player->next;
|
|
|
|
}
|
|
|
|
server->next_player_info = NO_PLAYER_INFO;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "unknown d3 packet\n");
|
|
|
|
print_packet(server, rawpkt, pktlen);
|
|
|
|
}
|
|
|
|
|
|
|
|
return DONE_FORCE;
|
|
|
|
}
|
|
|
|
|