node-gamedig/protocols/tribes1.js

105 lines
4.1 KiB
JavaScript

class Tribes1 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);
state.raw.teams = [];
for(let i = 0; i < state.raw.teamCount; i++) {
const teamName = this.readString(reader);
const teamValues = this.readValues(reader);
const teamInfo = {};
for (let i = 0; i < teamValues.length && i < teamFields.length; i++) {
let key = teamFields[i];
let value = teamValues[i];
if (key === 'ultra_base') key = 'name';
if (value === '%t') value = teamName;
if (['score','players'].includes(key)) 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 playerValues = this.readValues(reader);
const playerInfo = {};
for (let i = 0; i < playerValues.length && i < playerFields.length; i++) {
let key = playerFields[i];
let value = playerValues[i];
if (value === '%p') value = ping;
if (value === '%l') value = packetLoss;
if (value === '%t') value = teamNum;
if (value === '%n') value = name;
if (['score','ping','pl','kills','lvl'].includes(key)) 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) {
const str = this.readString(reader);
if (!str) return [];
return ('?'+str)
.split('\t')
.map((a) => a.substr(1).trim().toLowerCase())
.map((a) => a === 'team name' ? 'name' : a)
.map((a) => a === 'player name' ? 'name' : a);
}
readValues(reader) {
const str = this.readString(reader);
if (!str) return [];
return str
.split('\t')
.map((a) => a.trim());
}
readString(reader) {
const length = reader.uint(1);
if(!length) return '';
return reader.string({length:length});
}
}
module.exports = Tribes1;