mirror of
https://github.com/gamedig/node-gamedig.git
synced 2024-11-17 17:25:19 +01:00
Add support for Tribes 1: Starsiege
This commit is contained in:
parent
848600e45e
commit
802027c552
6 changed files with 105 additions and 436 deletions
|
@ -307,6 +307,7 @@ Games List
|
||||||
* Trackmania 2 (trackmania2) [[Additional Notes](#nadeo-shootmania--trackmania--etc)]
|
* Trackmania 2 (trackmania2) [[Additional Notes](#nadeo-shootmania--trackmania--etc)]
|
||||||
* Trackmania Forever (trackmaniaforever) [[Additional Notes](#nadeo-shootmania--trackmania--etc)]
|
* Trackmania Forever (trackmaniaforever) [[Additional Notes](#nadeo-shootmania--trackmania--etc)]
|
||||||
* Tremulous (tremulous) [[Separate Query Port](#separate-query-port)]
|
* Tremulous (tremulous) [[Separate Query Port](#separate-query-port)]
|
||||||
|
* Tribes 1: Starsiege (tribes1)
|
||||||
* Tribes: Vengeance (tribesvengeance) [[Separate Query Port](#separate-query-port)]
|
* Tribes: Vengeance (tribesvengeance) [[Separate Query Port](#separate-query-port)]
|
||||||
* Tron 2.0 (tron20) [[Separate Query Port](#separate-query-port)]
|
* Tron 2.0 (tron20) [[Separate Query Port](#separate-query-port)]
|
||||||
* Turok 2 (turok2) [[Separate Query Port](#separate-query-port)]
|
* Turok 2 (turok2) [[Separate Query Port](#separate-query-port)]
|
||||||
|
@ -356,7 +357,6 @@ Games List
|
||||||
* Savage 2: A Tortured Soul
|
* Savage 2: A Tortured Soul
|
||||||
* Sum of All Fears
|
* Sum of All Fears
|
||||||
* Teeworlds
|
* Teeworlds
|
||||||
* Tribes 1: Starsiege
|
|
||||||
* Tribes 2
|
* Tribes 2
|
||||||
* Vice City Multiplayer
|
* Vice City Multiplayer
|
||||||
* World in Conflict
|
* World in Conflict
|
||||||
|
|
|
@ -266,6 +266,7 @@ towerunite|Tower Unite|valve
|
||||||
trackmania2|Trackmania 2|nadeo||doc_notes=nadeo-shootmania--trackmania--etc
|
trackmania2|Trackmania 2|nadeo||doc_notes=nadeo-shootmania--trackmania--etc
|
||||||
trackmaniaforever|Trackmania Forever|nadeo||doc_notes=nadeo-shootmania--trackmania--etc
|
trackmaniaforever|Trackmania Forever|nadeo||doc_notes=nadeo-shootmania--trackmania--etc
|
||||||
tremulous|Tremulous|quake3|port_query=30720
|
tremulous|Tremulous|quake3|port_query=30720
|
||||||
|
tribes1|Tribes 1: Starsiege|tribes1|port=28001
|
||||||
tribesvengeance|Tribes: Vengeance|gamespy2|port=7777,port_query_offset=1
|
tribesvengeance|Tribes: Vengeance|gamespy2|port=7777,port_query_offset=1
|
||||||
tron20|Tron 2.0|gamespy2|port_query=27888
|
tron20|Tron 2.0|gamespy2|port_query=27888
|
||||||
turok2|Turok 2|gamespy1|port_query=12880
|
turok2|Turok 2|gamespy1|port_query=12880
|
||||||
|
|
103
protocols/tribes1.js
Normal file
103
protocols/tribes1.js
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
class Unreal2 extends require('./core') {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.encoding = 'latin1';
|
||||||
|
}
|
||||||
|
run(state) {
|
||||||
|
const queryBuffer = Buffer.from('b++');
|
||||||
|
this.udpSend(queryBuffer,(buffer) => {
|
||||||
|
const reader = this.reader(buffer);
|
||||||
|
const header = reader.string({length:4});
|
||||||
|
if (header !== 'c++b') {
|
||||||
|
this.fatal('Header response does not match: ' + header);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
state.raw.gametype = this.readString(reader);
|
||||||
|
state.raw.version = this.readString(reader);
|
||||||
|
state.name = this.readString(reader);
|
||||||
|
state.raw.dedicated = !!reader.uint(1);
|
||||||
|
state.password = !!reader.uint(1);
|
||||||
|
state.raw.playerCount = reader.uint(1);
|
||||||
|
state.maxplayers = reader.uint(1);
|
||||||
|
state.raw.cpu = reader.uint(2);
|
||||||
|
state.raw.mod = this.readString(reader);
|
||||||
|
state.raw.type = this.readString(reader);
|
||||||
|
state.map = this.readString(reader);
|
||||||
|
state.raw.motd = this.readString(reader);
|
||||||
|
state.raw.teamCount = reader.uint(1);
|
||||||
|
|
||||||
|
const teamFields = this.readFieldList(reader);
|
||||||
|
const playerFields = this.readFieldList(reader);
|
||||||
|
console.log(teamFields);
|
||||||
|
console.log(playerFields);
|
||||||
|
|
||||||
|
state.raw.teams = [];
|
||||||
|
for(let i = 0; i < state.raw.teamCount; i++) {
|
||||||
|
const teamName = this.readString(reader);
|
||||||
|
const teamValues = this.readString(reader)
|
||||||
|
.replace(/%t/g, teamName)
|
||||||
|
.split('\t')
|
||||||
|
.map((a) => a.trim());
|
||||||
|
|
||||||
|
const teamInfo = {};
|
||||||
|
for (let i = 0; i < teamValues.length && i < teamFields.length; i++) {
|
||||||
|
const key = teamFields[i];
|
||||||
|
let value = teamValues[i];
|
||||||
|
if (key === 'score' || key === 'players') value = parseInt(value);
|
||||||
|
teamInfo[key] = value;
|
||||||
|
}
|
||||||
|
state.raw.teams.push(teamInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let i = 0; i < state.raw.playerCount; i++) {
|
||||||
|
const ping = reader.uint(1) * 4;
|
||||||
|
const packetLoss = reader.uint(1);
|
||||||
|
const teamNum = reader.uint(1);
|
||||||
|
const name = this.readString(reader);
|
||||||
|
const valuesStr = this.readString(reader);
|
||||||
|
if (!valuesStr) continue;
|
||||||
|
const playerValues = valuesStr
|
||||||
|
.replace(/%p/g, ping)
|
||||||
|
.replace(/%l/g, packetLoss)
|
||||||
|
.replace(/%t/g, teamNum)
|
||||||
|
.replace(/%n/g, name)
|
||||||
|
.split('\t')
|
||||||
|
.map((a) => a.trim());
|
||||||
|
|
||||||
|
const playerInfo = {};
|
||||||
|
for (let i = 0; i < playerValues.length && i < playerFields.length; i++) {
|
||||||
|
const key = playerFields[i];
|
||||||
|
let value = playerValues[i];
|
||||||
|
if (key === 'score' || key === 'ping' || key === 'pl') value = parseInt(value);
|
||||||
|
if (key === 'team') {
|
||||||
|
const teamId = parseInt(value);
|
||||||
|
if (teamId >= 0 && teamId < state.raw.teams.length && state.raw.teams[teamId].name) {
|
||||||
|
value = state.raw.teams[teamId].name;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
playerInfo[key] = value;
|
||||||
|
}
|
||||||
|
state.players.push(playerInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.finish(state);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
readFieldList(reader) {
|
||||||
|
return ('?'+this.readString(reader))
|
||||||
|
.split('\t')
|
||||||
|
.map((a) => a.substr(1).toLowerCase())
|
||||||
|
.map((a) => a === 'team name' ? 'name' : a)
|
||||||
|
.map((a) => a === 'player name' ? 'name' : a);
|
||||||
|
}
|
||||||
|
readString(reader) {
|
||||||
|
const length = reader.uint(1);
|
||||||
|
if(!length) return '';
|
||||||
|
return reader.string({length:length});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Unreal2;
|
|
@ -1,63 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* This file is part of GameQ.
|
|
||||||
*
|
|
||||||
* GameQ is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* GameQ is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* $Id: tribes.php,v 1.1 2007/07/07 14:20:21 tombuskens Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
[tribes]
|
|
||||||
status = "b++"
|
|
||||||
|
|
||||||
|
|
||||||
require_once GAMEQ_BASE . 'Protocol.php';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tribes protocol
|
|
||||||
*
|
|
||||||
* @author Tom Buskens <t.buskens@deviation.nl>
|
|
||||||
* @version $Revision: 1.1 $
|
|
||||||
*/
|
|
||||||
class GameQ_Protocol_tribes extends GameQ_Protocol
|
|
||||||
{
|
|
||||||
public function status()
|
|
||||||
{
|
|
||||||
// Header
|
|
||||||
if ($this->p->read(4) != 'c++b') {
|
|
||||||
throw new GameQ_ParsingException($this->p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variables
|
|
||||||
$this->r->add('game', $this->p->readPascalString());
|
|
||||||
$this->r->add('version', $this->p->readPascalString());
|
|
||||||
$this->r->add('hostname', $this->p->readPascalString());
|
|
||||||
$this->r->add('dedicated', $this->p->readInt8());
|
|
||||||
$this->r->add('password', $this->p->readInt8());
|
|
||||||
$this->r->add('num_players', $this->p->readInt8());
|
|
||||||
$this->r->add('max_players', $this->p->readInt8());
|
|
||||||
$this->r->add('cpu_lsb', $this->p->readInt8());
|
|
||||||
$this->r->add('cpu_msb', $this->p->readInt8());
|
|
||||||
$this->r->add('mod', $this->p->readPascalString());
|
|
||||||
$this->r->add('gametype', $this->p->readPascalString());
|
|
||||||
$this->r->add('map', $this->p->readPascalString());
|
|
||||||
$this->r->add('motd', $this->p->readPascalString());
|
|
||||||
$this->r->add('teamcount', $this->p->readInt8()); // Not sure
|
|
||||||
|
|
||||||
// TODO: player listing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
|
@ -1,125 +0,0 @@
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------------------------------\
|
|
||||||
| |
|
|
||||||
| [ LIVE GAME SERVER LIST ] [ © RICHARD PERRY FROM GREYCUBE.COM ] |
|
|
||||||
| |
|
|
||||||
| Released under the terms and conditions of the GNU General Public License Version 3 (http://gnu.org) |
|
|
||||||
| |
|
|
||||||
\-----------------------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
function lgsl_query_23(&$server, &$lgsl_need, &$lgsl_fp)
|
|
||||||
{
|
|
||||||
//---------------------------------------------------------+
|
|
||||||
// REFERENCE:
|
|
||||||
// http://siteinthe.us
|
|
||||||
// http://www.tribesmasterserver.com
|
|
||||||
|
|
||||||
fwrite($lgsl_fp, "b++");
|
|
||||||
|
|
||||||
$buffer = fread($lgsl_fp, 4096);
|
|
||||||
|
|
||||||
if (!$buffer) { return FALSE; }
|
|
||||||
|
|
||||||
$buffer = substr($buffer, 4); // REMOVE HEADER
|
|
||||||
|
|
||||||
//---------------------------------------------------------+
|
|
||||||
|
|
||||||
$server['s']['game'] = lgsl_cut_pascal($buffer);
|
|
||||||
$server['e']['version'] = lgsl_cut_pascal($buffer);
|
|
||||||
$server['s']['name'] = lgsl_cut_pascal($buffer);
|
|
||||||
$server['e']['dedicated'] = ord(lgsl_cut_byte($buffer, 1));
|
|
||||||
$server['s']['password'] = ord(lgsl_cut_byte($buffer, 1));
|
|
||||||
$server['s']['players'] = ord(lgsl_cut_byte($buffer, 1));
|
|
||||||
$server['s']['playersmax'] = ord(lgsl_cut_byte($buffer, 1));
|
|
||||||
$server['e']['cpu'] = lgsl_unpack(lgsl_cut_byte($buffer, 2), "S");
|
|
||||||
$server['e']['mod'] = lgsl_cut_pascal($buffer);
|
|
||||||
$server['e']['type'] = lgsl_cut_pascal($buffer);
|
|
||||||
$server['s']['map'] = lgsl_cut_pascal($buffer);
|
|
||||||
$server['e']['motd'] = lgsl_cut_pascal($buffer);
|
|
||||||
$server['e']['teams'] = ord(lgsl_cut_byte($buffer, 1));
|
|
||||||
|
|
||||||
//---------------------------------------------------------+
|
|
||||||
|
|
||||||
$team_field = "?".lgsl_cut_pascal($buffer);
|
|
||||||
$team_field = split("\t", $team_field);
|
|
||||||
|
|
||||||
foreach ($team_field as $key => $value)
|
|
||||||
{
|
|
||||||
$value = substr($value, 1);
|
|
||||||
$value = strtolower($value);
|
|
||||||
$team_field[$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------+
|
|
||||||
|
|
||||||
$player_field = "?".lgsl_cut_pascal($buffer);
|
|
||||||
$player_field = split("\t", $player_field);
|
|
||||||
|
|
||||||
foreach ($player_field as $key => $value)
|
|
||||||
{
|
|
||||||
$value = substr($value, 1);
|
|
||||||
$value = strtolower($value);
|
|
||||||
|
|
||||||
if ($value == "player name") { $value = "name"; }
|
|
||||||
|
|
||||||
$player_field[$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$player_field[] = "unknown_1";
|
|
||||||
$player_field[] = "unknown_2";
|
|
||||||
|
|
||||||
//---------------------------------------------------------+
|
|
||||||
|
|
||||||
for ($i=0; $i<$server['e']['teams']; $i++)
|
|
||||||
{
|
|
||||||
$team_name = lgsl_cut_pascal($buffer);
|
|
||||||
$team_info = lgsl_cut_pascal($buffer);
|
|
||||||
|
|
||||||
if (!$team_info) { continue; }
|
|
||||||
|
|
||||||
$team_info = str_replace("%t", $team_name, $team_info);
|
|
||||||
$team_info = split("\t", $team_info);
|
|
||||||
|
|
||||||
foreach ($team_info as $key => $value)
|
|
||||||
{
|
|
||||||
$field = $team_field[$key];
|
|
||||||
$value = trim($value);
|
|
||||||
|
|
||||||
if ($field == "team name") { $field = "name"; }
|
|
||||||
|
|
||||||
$server['t'][$i][$field] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------+
|
|
||||||
|
|
||||||
for ($i=0; $i<$server['s']['players']; $i++)
|
|
||||||
{
|
|
||||||
$player_bits = array();
|
|
||||||
$player_bits[] = ord(lgsl_cut_byte($buffer, 1)) * 4; // %p = PING
|
|
||||||
$player_bits[] = ord(lgsl_cut_byte($buffer, 1)); // %l = PACKET LOSS
|
|
||||||
$player_bits[] = ord(lgsl_cut_byte($buffer, 1)); // %t = TEAM
|
|
||||||
$player_bits[] = lgsl_cut_pascal($buffer); // %n = PLAYER NAME
|
|
||||||
$player_info = lgsl_cut_pascal($buffer);
|
|
||||||
|
|
||||||
if (!$player_info) { continue; }
|
|
||||||
|
|
||||||
$player_info = str_replace(array("%p","%l","%t","%n"), $player_bits, $player_info);
|
|
||||||
$player_info = split("\t", $player_info);
|
|
||||||
|
|
||||||
foreach ($player_info as $key => $value)
|
|
||||||
{
|
|
||||||
$field = $player_field[$key];
|
|
||||||
$value = trim($value);
|
|
||||||
|
|
||||||
if ($field == "team") { $value = $server['t'][$value]['name']; }
|
|
||||||
|
|
||||||
$server['p'][$i][$field] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------+
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
|
@ -1,247 +0,0 @@
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* TRIBES */
|
|
||||||
char tribes_info[] = { '`', '*', '*' };
|
|
||||||
char tribes_players[] = { 'b', '*', '*' };
|
|
||||||
/* This is what the game sends to get minimal status
|
|
||||||
{ '\020', '\03', '\377', 0, (unsigned char)0xc5, 6 };
|
|
||||||
*/
|
|
||||||
char tribes_info_reponse[] = { 'a', '*', '*', 'b' };
|
|
||||||
char tribes_players_reponse[] = { 'c', '*', '*', 'b' };
|
|
||||||
char tribes_masterquery[] = { 0x10, 0x3, '\377', 0, 0x2 };
|
|
||||||
char tribes_master_response[] = { 0x10, 0x6 };
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
/* TRIBES */
|
|
||||||
TRIBES_SERVER, /* id */
|
|
||||||
"TBS", /* type_prefix */
|
|
||||||
"tbs", /* type_string */
|
|
||||||
"-tbs", /* type_option */
|
|
||||||
"Tribes", /* game_name */
|
|
||||||
0, /* master */
|
|
||||||
TRIBES_DEFAULT_PORT, /* default_port */
|
|
||||||
0, /* port_offset */
|
|
||||||
TF_SINGLE_QUERY, /* flags */
|
|
||||||
"game", /* game_rule */
|
|
||||||
"TRIBES", /* template_var */
|
|
||||||
(char*) &tribes_info, /* status_packet */
|
|
||||||
sizeof( tribes_info), /* status_len */
|
|
||||||
(char*) &tribes_players, /* player_packet */
|
|
||||||
sizeof( tribes_players), /* player_len */
|
|
||||||
(char*) &tribes_players, /* rule_packet */
|
|
||||||
sizeof( tribes_players), /* rule_len */
|
|
||||||
NULL, /* master_packet */
|
|
||||||
0, /* master_len */
|
|
||||||
NULL, /* master_protocol */
|
|
||||||
NULL, /* master_query */
|
|
||||||
display_tribes_player_info, /* display_player_func */
|
|
||||||
display_server_rules, /* display_rule_func */
|
|
||||||
raw_display_tribes_player_info, /* display_raw_player_func */
|
|
||||||
raw_display_server_rules, /* display_raw_rule_func */
|
|
||||||
xml_display_tribes_player_info, /* display_xml_player_func */
|
|
||||||
xml_display_server_rules, /* display_xml_rule_func */
|
|
||||||
send_tribes_request_packet, /* status_query_func */
|
|
||||||
NULL, /* rule_query_func */
|
|
||||||
NULL, /* player_query_func */
|
|
||||||
deal_with_tribes_packet, /* packet_func */
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
query_status_t deal_with_tribes_packet(struct qserver *server, char *rawpkt, int pktlen)
|
|
||||||
{
|
|
||||||
unsigned char *pkt, *end;
|
|
||||||
int len, pnum, ping, packet_loss, n_teams, t;
|
|
||||||
struct player *player;
|
|
||||||
struct player **teams = NULL;
|
|
||||||
struct player **last_player = &server->players;
|
|
||||||
char buf[24];
|
|
||||||
|
|
||||||
debug( 2, "deal_with_tribes_packet %p, %d", server, pktlen );
|
|
||||||
|
|
||||||
if (server->server_name == NULL)
|
|
||||||
{
|
|
||||||
server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gettimeofday(&server->packet_time1, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pktlen < sizeof(tribes_info_reponse))
|
|
||||||
{
|
|
||||||
return PKT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strncmp(rawpkt, tribes_players_reponse, sizeof(tribes_players_reponse)) != 0)
|
|
||||||
{
|
|
||||||
return PKT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt = (unsigned char*) &rawpkt[sizeof(tribes_info_reponse)];
|
|
||||||
|
|
||||||
len = *pkt; /* game name: "Tribes" */
|
|
||||||
add_nrule(server, "gamename", (char*)pkt + 1, len);
|
|
||||||
pkt += len + 1;
|
|
||||||
len = *pkt; /* version */
|
|
||||||
add_nrule(server, "version", (char*)pkt + 1, len);
|
|
||||||
pkt += len + 1;
|
|
||||||
len = *pkt; /* server name */
|
|
||||||
server->server_name = strndup((char*)pkt + 1, len);
|
|
||||||
pkt += len + 1;
|
|
||||||
add_rule(server, "dedicated", *pkt ? "1" : "0", NO_FLAGS);
|
|
||||||
pkt++; /* flag: dedicated server */
|
|
||||||
add_rule(server, "needpass", *pkt ? "1" : "0", NO_FLAGS);
|
|
||||||
pkt++; /* flag: password on server */
|
|
||||||
server->num_players = *pkt++;
|
|
||||||
server->max_players = *pkt++;
|
|
||||||
|
|
||||||
sprintf(buf, "%u", (unsigned int)pkt[0] + (unsigned int)pkt[1] *256);
|
|
||||||
add_rule(server, "cpu", buf, NO_FLAGS);
|
|
||||||
pkt++; /* cpu speed, lsb */
|
|
||||||
pkt++; /* cpu speed, msb */
|
|
||||||
|
|
||||||
len = *pkt; /* Mod (game) */
|
|
||||||
add_nrule(server, "mods", (char*)pkt + 1, len);
|
|
||||||
pkt += len + 1;
|
|
||||||
|
|
||||||
len = *pkt; /* game (mission): "C&H" */
|
|
||||||
add_nrule(server, "game", (char*)pkt + 1, len);
|
|
||||||
pkt += len + 1;
|
|
||||||
|
|
||||||
len = *pkt; /* Mission (map) */
|
|
||||||
server->map_name = strndup((char*)pkt + 1, len);
|
|
||||||
pkt += len + 1;
|
|
||||||
|
|
||||||
len = *pkt; /* description (contains Admin: and Email: ) */
|
|
||||||
debug( 2, "%.*s\n", len, pkt + 1);
|
|
||||||
pkt += len + 1;
|
|
||||||
|
|
||||||
n_teams = *pkt++; /* number of teams */
|
|
||||||
if (n_teams == 255)
|
|
||||||
{
|
|
||||||
return PKT_ERROR;
|
|
||||||
}
|
|
||||||
sprintf(buf, "%d", n_teams);
|
|
||||||
add_rule(server, "numteams", buf, NO_FLAGS);
|
|
||||||
|
|
||||||
len = *pkt; /* first title */
|
|
||||||
debug( 2, "%.*s\n", len, pkt + 1);
|
|
||||||
pkt += len + 1;
|
|
||||||
|
|
||||||
len = *pkt; /* second title */
|
|
||||||
debug( 2, "%.*s\n", len, pkt + 1);
|
|
||||||
pkt += len + 1;
|
|
||||||
|
|
||||||
if (n_teams > 1)
|
|
||||||
{
|
|
||||||
teams = (struct player **)calloc(1, sizeof(struct player*) * n_teams);
|
|
||||||
for (t = 0; t < n_teams; t++)
|
|
||||||
{
|
|
||||||
teams[t] = (struct player*)calloc(1, sizeof(struct player));
|
|
||||||
teams[t]->number = TRIBES_TEAM;
|
|
||||||
teams[t]->team = t;
|
|
||||||
len = *pkt; /* team name */
|
|
||||||
teams[t]->name = strndup((char*)pkt + 1, len);
|
|
||||||
debug( 2, "team#0 <%.*s>\n", len, pkt + 1);
|
|
||||||
pkt += len + 1;
|
|
||||||
|
|
||||||
len = *pkt; /* team score */
|
|
||||||
if (len > 2)
|
|
||||||
{
|
|
||||||
strncpy(buf, (char*)pkt + 1+3, len - 3);
|
|
||||||
buf[len - 3] = '\0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
debug( 2, "%s score len %d\n", server->arg, len);
|
|
||||||
buf[0] = '\0';
|
|
||||||
}
|
|
||||||
teams[t]->frags = atoi(buf);
|
|
||||||
debug( 2, "team#0 <%.*s>\n", len - 3, pkt + 1+3);
|
|
||||||
pkt += len + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
len = *pkt; /* DM team? */
|
|
||||||
debug( 2, "%.*s\n", len, pkt + 1);
|
|
||||||
pkt += len + 1;
|
|
||||||
pkt++;
|
|
||||||
n_teams = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pnum = 0;
|
|
||||||
while ((char*)pkt < (rawpkt + pktlen))
|
|
||||||
{
|
|
||||||
ping = (unsigned int) *pkt << 2;
|
|
||||||
pkt++;
|
|
||||||
packet_loss = *pkt;
|
|
||||||
pkt++;
|
|
||||||
debug( 2, "player#%d, team #%d\n", pnum, (int) *pkt);
|
|
||||||
pkt++;
|
|
||||||
len = *pkt;
|
|
||||||
if ((char*)pkt + len > (rawpkt + pktlen))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
player = (struct player*)calloc(1, sizeof(struct player));
|
|
||||||
player->team = pkt[ - 1];
|
|
||||||
if (n_teams && player->team < n_teams)
|
|
||||||
{
|
|
||||||
player->team_name = teams[player->team]->name;
|
|
||||||
}
|
|
||||||
else if (player->team == 255 && n_teams)
|
|
||||||
{
|
|
||||||
player->team_name = "Unknown";
|
|
||||||
}
|
|
||||||
player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM;
|
|
||||||
player->ping = ping;
|
|
||||||
player->packet_loss = packet_loss;
|
|
||||||
player->name = strndup((char*)pkt + 1, len);
|
|
||||||
debug( 2, "player#%d, name %.*s\n", pnum, len, pkt + 1);
|
|
||||||
pkt += len + 1;
|
|
||||||
len = *pkt;
|
|
||||||
debug( 2, "player#%d, info <%.*s>\n", pnum, len, pkt + 1);
|
|
||||||
end = (unsigned char*)strchr((char*)pkt + 9, 0x9);
|
|
||||||
if (end)
|
|
||||||
{
|
|
||||||
strncpy(buf, (char*)pkt + 9, end - (pkt + 9));
|
|
||||||
buf[end - (pkt + 9)] = '\0';
|
|
||||||
player->frags = atoi(buf);
|
|
||||||
debug( 2, "player#%d, score <%.*s>\n", pnum, (unsigned)(end - (pkt + 9)), pkt + 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
*last_player = player;
|
|
||||||
last_player = &player->next;
|
|
||||||
|
|
||||||
pkt += len + 1;
|
|
||||||
pnum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (t = n_teams; t;)
|
|
||||||
{
|
|
||||||
t--;
|
|
||||||
teams[t]->next = server->players;
|
|
||||||
server->players = teams[t];
|
|
||||||
}
|
|
||||||
free(teams);
|
|
||||||
|
|
||||||
return DONE_AUTO;
|
|
||||||
}
|
|
Loading…
Reference in a new issue