mirror of
https://github.com/gamedig/node-gamedig.git
synced 2024-11-18 17:50:37 +01:00
447 lines
9 KiB
Text
447 lines
9 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
|
||
|
*/
|
||
|
|
||
|
|
||
|
char ravenshield_serverquery[] = "REPORT";
|
||
|
|
||
|
|
||
|
{
|
||
|
/* RAVENSHIELD PROTOCOL */
|
||
|
RAVENSHIELD_SERVER, /* id */
|
||
|
"RSS", /* type_prefix */
|
||
|
"rss", /* type_string */
|
||
|
"-rss", /* type_option */
|
||
|
"Ravenshield", /* game_name */
|
||
|
0, /* master */
|
||
|
RAVENSHIELD_DEFAULT_PORT, /* default_port */
|
||
|
1000, /* port_offset */
|
||
|
TF_QUERY_ARG, /* flags */
|
||
|
"gametype", /* game_rule */
|
||
|
"RAVENSHIELD", /* template_var */
|
||
|
(char*)ravenshield_serverquery, /* status_packet */
|
||
|
sizeof( ravenshield_serverquery ) - 1, /* 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_ravenshield_player_info, /* display_player_func */
|
||
|
display_server_rules, /* display_rule_func */
|
||
|
raw_display_ravenshield_player_info, /* display_raw_player_func */
|
||
|
raw_display_server_rules, /* display_raw_rule_func */
|
||
|
xml_display_ravenshield_player_info, /* display_xml_player_func */
|
||
|
xml_display_server_rules, /* display_xml_rule_func */
|
||
|
send_qserver_request_packet, /* status_query_func */
|
||
|
NULL, /* rule_query_func */
|
||
|
NULL, /* player_query_func */
|
||
|
deal_with_ravenshield_packet, /* packet_func */
|
||
|
},
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
query_status_t deal_with_ravenshield_packet(struct qserver *server, char *rawpkt, int pktlen)
|
||
|
{
|
||
|
char *s, *key, *value;
|
||
|
|
||
|
debug( 2, "deal_with_ravenshield_packet %p, %d", server, pktlen );
|
||
|
|
||
|
server->n_servers++;
|
||
|
if (NULL == server->server_name)
|
||
|
{
|
||
|
server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gettimeofday(&server->packet_time1, NULL);
|
||
|
}
|
||
|
|
||
|
rawpkt[pktlen] = '\0';
|
||
|
|
||
|
s = rawpkt;
|
||
|
while (*s)
|
||
|
{
|
||
|
// Find the seperator
|
||
|
while (*s && *s != '\xB6')
|
||
|
{
|
||
|
s++;
|
||
|
}
|
||
|
|
||
|
if (! *s)
|
||
|
{
|
||
|
// Hit the end no more
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// key start
|
||
|
key = ++s;
|
||
|
while (*s && *s != ' ')
|
||
|
{
|
||
|
s++;
|
||
|
}
|
||
|
if (*s != ' ')
|
||
|
{
|
||
|
// malformed
|
||
|
break;
|
||
|
}
|
||
|
*s++ = '\0';
|
||
|
// key end
|
||
|
// value start
|
||
|
value = s;
|
||
|
|
||
|
while (*s && *s != '\xB6')
|
||
|
{
|
||
|
s++;
|
||
|
}
|
||
|
|
||
|
if (*s == '\xB6')
|
||
|
{
|
||
|
*(s - 1) = '\0';
|
||
|
}
|
||
|
|
||
|
// Decode current key par
|
||
|
if (0 == strcmp("A1", key))
|
||
|
{
|
||
|
// Max players
|
||
|
server->max_players = atoi(value);
|
||
|
}
|
||
|
else if (0 == strcmp("A2", key))
|
||
|
{
|
||
|
// TeamKillerPenalty
|
||
|
add_rule(server, "TeamKillerPenalty", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("B1", key))
|
||
|
{
|
||
|
// Current players
|
||
|
server->num_players = atoi(value);
|
||
|
}
|
||
|
else if (0 == strcmp("B2", key))
|
||
|
{
|
||
|
// AllowRadar
|
||
|
add_rule(server, "AllowRadar", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("D2", key))
|
||
|
{
|
||
|
// Version info
|
||
|
add_rule(server, "Version", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("E1", key))
|
||
|
{
|
||
|
// Current map
|
||
|
server->map_name = strdup(value);
|
||
|
}
|
||
|
else if (0 == strcmp("E2", key))
|
||
|
{
|
||
|
// Unknown
|
||
|
}
|
||
|
else if (0 == strcmp("F1", key))
|
||
|
{
|
||
|
// Game type
|
||
|
server->game = find_ravenshield_game(value);
|
||
|
add_rule(server, server->type->game_rule, server->game, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("F2", key))
|
||
|
{
|
||
|
// Unknown
|
||
|
}
|
||
|
else if (0 == strcmp("G1", key))
|
||
|
{
|
||
|
// Password
|
||
|
add_rule(server, "Password", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("G2", key))
|
||
|
{
|
||
|
// Query port
|
||
|
}
|
||
|
else if (0 == strcmp("H1", key))
|
||
|
{
|
||
|
// Unknown
|
||
|
}
|
||
|
else if (0 == strcmp("H2", key))
|
||
|
{
|
||
|
// Number of Terrorists
|
||
|
add_rule(server, "nbTerro", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("I1", key))
|
||
|
{
|
||
|
// Server name
|
||
|
server->server_name = strdup(value);
|
||
|
}
|
||
|
else if (0 == strcmp("I2", key))
|
||
|
{
|
||
|
// Unknown
|
||
|
}
|
||
|
else if (0 == strcmp("J1", key))
|
||
|
{
|
||
|
// Game Type Order
|
||
|
// Not pretty ignore for now
|
||
|
//add_rule( server, "Game Type Order", value, NO_FLAGS );
|
||
|
}
|
||
|
else if (0 == strcmp("J2", key))
|
||
|
{
|
||
|
// RotateMap
|
||
|
add_rule(server, "RotateMap", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("K1", key))
|
||
|
{
|
||
|
// Map Cycle
|
||
|
// Not pretty ignore for now
|
||
|
//add_rule( server, "Map Cycle", value, NO_FLAGS );
|
||
|
}
|
||
|
else if (0 == strcmp("K2", key))
|
||
|
{
|
||
|
// Force First Person Weapon
|
||
|
add_rule(server, "ForceFPersonWeapon", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("L1", key))
|
||
|
{
|
||
|
// Players names
|
||
|
int player_number = 0;
|
||
|
char *n = value;
|
||
|
|
||
|
if (*n == '/')
|
||
|
{
|
||
|
// atleast 1 player
|
||
|
n++;
|
||
|
while (*n && *n != '\xB6')
|
||
|
{
|
||
|
char *player_name = n;
|
||
|
while (*n && *n != '/' && *n != '\xB6')
|
||
|
{
|
||
|
n++;
|
||
|
}
|
||
|
|
||
|
if (*n == '/')
|
||
|
{
|
||
|
*n++ = '\0';
|
||
|
}
|
||
|
else if (*n == '\xB6')
|
||
|
{
|
||
|
*(n - 1) = '\0';
|
||
|
}
|
||
|
|
||
|
if (0 != strlen(player_name))
|
||
|
{
|
||
|
struct player *player = add_player(server, player_number);
|
||
|
if (NULL != player)
|
||
|
{
|
||
|
player->name = strdup(player_name);
|
||
|
}
|
||
|
player_number++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (0 == strcmp("L3", key))
|
||
|
{
|
||
|
// PunkBuster state
|
||
|
add_rule(server, "PunkBuster", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("M1", key))
|
||
|
{
|
||
|
// Players times
|
||
|
int player_number = 0;
|
||
|
char *n = value;
|
||
|
if (*n == '/')
|
||
|
{
|
||
|
// atleast 1 player
|
||
|
n++;
|
||
|
while (*n && *n != '\xB6')
|
||
|
{
|
||
|
char *time = n;
|
||
|
while (*n && *n != '/' && *n != '\xB6')
|
||
|
{
|
||
|
n++;
|
||
|
}
|
||
|
|
||
|
if (*n == '/')
|
||
|
{
|
||
|
*n++ = '\0';
|
||
|
}
|
||
|
else if (*n == '\xB6')
|
||
|
{
|
||
|
*(n - 1) = '\0';
|
||
|
}
|
||
|
|
||
|
if (0 != strlen(time))
|
||
|
{
|
||
|
int mins, seconds;
|
||
|
if (2 == sscanf(time, "%d:%d", &mins, &seconds))
|
||
|
{
|
||
|
struct player *player = get_player_by_number(server, player_number);
|
||
|
if (NULL != player)
|
||
|
{
|
||
|
player->connect_time = mins * 60+seconds;
|
||
|
}
|
||
|
}
|
||
|
player_number++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (0 == strcmp("N1", key))
|
||
|
{
|
||
|
// Players ping
|
||
|
int player_number = 0;
|
||
|
char *n = value;
|
||
|
if (*n == '/')
|
||
|
{
|
||
|
// atleast 1 player
|
||
|
n++;
|
||
|
while (*n && *n != '\xB6')
|
||
|
{
|
||
|
char *ping = n;
|
||
|
while (*n && *n != '/' && *n != '\xB6')
|
||
|
{
|
||
|
n++;
|
||
|
}
|
||
|
|
||
|
if (*n == '/')
|
||
|
{
|
||
|
*n++ = '\0';
|
||
|
}
|
||
|
else if (*n == '\xB6')
|
||
|
{
|
||
|
*(n - 1) = '\0';
|
||
|
}
|
||
|
|
||
|
if (0 != strlen(ping))
|
||
|
{
|
||
|
struct player *player = get_player_by_number(server, player_number);
|
||
|
if (NULL != player)
|
||
|
{
|
||
|
player->ping = atoi(ping);
|
||
|
} player_number++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (0 == strcmp("O1", key))
|
||
|
{
|
||
|
// Players fags
|
||
|
int player_number = 0;
|
||
|
char *n = value;
|
||
|
if (*n == '/')
|
||
|
{
|
||
|
// atleast 1 player
|
||
|
n++;
|
||
|
while (*n && *n != '\xB6')
|
||
|
{
|
||
|
char *frags = n;
|
||
|
while (*n && *n != '/' && *n != '\xB6')
|
||
|
{
|
||
|
n++;
|
||
|
}
|
||
|
|
||
|
if (*n == '/')
|
||
|
{
|
||
|
*n++ = '\0';
|
||
|
}
|
||
|
else if (*n == '\xB6')
|
||
|
{
|
||
|
*(n - 1) = '\0';
|
||
|
}
|
||
|
|
||
|
if (0 != strlen(frags))
|
||
|
{
|
||
|
struct player *player = get_player_by_number(server, player_number);
|
||
|
if (NULL != player)
|
||
|
{
|
||
|
player->frags = atoi(frags);
|
||
|
} player_number++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (0 == strcmp("P1", key))
|
||
|
{
|
||
|
// Game port
|
||
|
// Not pretty ignore for now
|
||
|
/*
|
||
|
change_server_port( server, atoi( value ), 0 );
|
||
|
*/
|
||
|
}
|
||
|
else if (0 == strcmp("Q1", key))
|
||
|
{
|
||
|
// RoundsPerMatch
|
||
|
add_rule(server, "RoundsPerMatch", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("R1", key))
|
||
|
{
|
||
|
// RoundTime
|
||
|
add_rule(server, "RoundTime", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("S1", key))
|
||
|
{
|
||
|
// BetweenRoundTime
|
||
|
add_rule(server, "BetweenRoundTime", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("T1", key))
|
||
|
{
|
||
|
// BombTime
|
||
|
add_rule(server, "BombTime", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("W1", key))
|
||
|
{
|
||
|
// ShowNames
|
||
|
add_rule(server, "ShowNames", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("X1", key))
|
||
|
{
|
||
|
// InternetServer
|
||
|
add_rule(server, "InternetServer", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("Y1", key))
|
||
|
{
|
||
|
// FriendlyFire
|
||
|
add_rule(server, "FriendlyFire", value, NO_FLAGS);
|
||
|
}
|
||
|
else if (0 == strcmp("Z1", key))
|
||
|
{
|
||
|
// Autobalance
|
||
|
add_rule(server, "Autobalance", value, NO_FLAGS);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return DONE_FORCE;
|
||
|
}
|
||
|
|
||
|
|
||
|
char *find_ravenshield_game(char *gameno)
|
||
|
{
|
||
|
switch (atoi(gameno))
|
||
|
{
|
||
|
case 8:
|
||
|
return strdup("Team Deathmatch");
|
||
|
break;
|
||
|
case 13:
|
||
|
return strdup("Deathmatch");
|
||
|
break;
|
||
|
case 14:
|
||
|
return strdup("Team Deathmatch");
|
||
|
break;
|
||
|
case 15:
|
||
|
return strdup("Bomb");
|
||
|
break;
|
||
|
case 16:
|
||
|
return strdup("Escort Pilot");
|
||
|
break;
|
||
|
default:
|
||
|
// 1.50 and above actually uses a string so
|
||
|
// return that
|
||
|
return strdup(gameno);
|
||
|
break;
|
||
|
}
|
||
|
}
|