2023-09-14 22:28:31 +02:00
|
|
|
import Core from './core.js';
|
2019-01-07 01:52:03 +01:00
|
|
|
|
2023-09-14 22:28:31 +02:00
|
|
|
export default class tribes1 extends Core {
|
2018-03-18 06:54:56 +01:00
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
this.encoding = 'latin1';
|
2019-01-13 07:01:55 +01:00
|
|
|
this.requestByte = 0x62;
|
|
|
|
this.responseByte = 0x63;
|
|
|
|
this.challenge = 0x01;
|
2018-03-18 06:54:56 +01:00
|
|
|
}
|
2019-01-10 13:03:07 +01:00
|
|
|
|
|
|
|
async run(state) {
|
2019-01-13 07:01:55 +01:00
|
|
|
const query = Buffer.alloc(3);
|
|
|
|
query.writeUInt8(this.requestByte, 0);
|
|
|
|
query.writeUInt16LE(this.challenge, 1);
|
|
|
|
const reader = await this.udpSend(query,(buffer) => {
|
2018-03-18 06:54:56 +01:00
|
|
|
const reader = this.reader(buffer);
|
2019-01-13 07:01:55 +01:00
|
|
|
const responseByte = reader.uint(1);
|
|
|
|
if (responseByte !== this.responseByte) {
|
2023-09-18 09:48:24 +02:00
|
|
|
this.logger.debug('Unexpected response byte');
|
2019-01-13 07:01:55 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const challenge = reader.uint(2);
|
|
|
|
if (challenge !== this.challenge) {
|
2023-09-18 09:48:24 +02:00
|
|
|
this.logger.debug('Unexpected challenge');
|
2019-01-13 07:01:55 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const requestByte = reader.uint(1);
|
|
|
|
if (requestByte !== this.requestByte) {
|
2023-09-18 09:48:24 +02:00
|
|
|
this.logger.debug('Unexpected request byte');
|
2019-01-10 13:03:07 +01:00
|
|
|
return;
|
2018-03-18 06:54:56 +01:00
|
|
|
}
|
2019-01-10 13:03:07 +01:00
|
|
|
return reader;
|
|
|
|
});
|
2018-03-18 06:54:56 +01:00
|
|
|
|
2019-01-10 13:03:07 +01:00
|
|
|
state.raw.gametype = this.readString(reader);
|
2019-01-13 07:01:55 +01:00
|
|
|
const isStarsiege2009 = state.raw.gametype === 'Starsiege';
|
2019-01-10 13:03:07 +01:00
|
|
|
state.raw.version = this.readString(reader);
|
|
|
|
state.name = this.readString(reader);
|
2019-01-13 07:01:55 +01:00
|
|
|
|
|
|
|
if (isStarsiege2009) {
|
|
|
|
state.password = !!reader.uint(1);
|
|
|
|
state.raw.dedicated = !!reader.uint(1);
|
|
|
|
state.raw.dropInProgress = !!reader.uint(1);
|
|
|
|
state.raw.gameInProgress = !!reader.uint(1);
|
|
|
|
state.raw.playerCount = reader.uint(4);
|
|
|
|
state.maxplayers = reader.uint(4);
|
|
|
|
state.raw.teamPlay = reader.uint(1);
|
|
|
|
state.map = this.readString(reader);
|
|
|
|
state.raw.cpuSpeed = reader.uint(2);
|
|
|
|
state.raw.factoryVeh = reader.uint(1);
|
|
|
|
state.raw.allowTecmix = reader.uint(1);
|
|
|
|
state.raw.spawnLimit = reader.uint(4);
|
|
|
|
state.raw.fragLimit = reader.uint(4);
|
|
|
|
state.raw.timeLimit = reader.uint(4);
|
|
|
|
state.raw.techLimit = reader.uint(4);
|
|
|
|
state.raw.combatLimit = reader.uint(4);
|
|
|
|
state.raw.massLimit = reader.uint(4);
|
|
|
|
state.raw.playersSent = reader.uint(4);
|
|
|
|
const teams = {1:'yellow', 2:'blue', 4:'red', 8:'purple'};
|
|
|
|
while (!reader.done()) {
|
|
|
|
const player = {};
|
|
|
|
player.name = this.readString(reader);
|
|
|
|
const teamId = reader.uint(1);
|
|
|
|
const team = teams[teamId];
|
|
|
|
if (team) player.team = teams[teamId];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-10 13:03:07 +01:00
|
|
|
state.raw.dedicated = !!reader.uint(1);
|
|
|
|
state.password = !!reader.uint(1);
|
|
|
|
state.raw.playerCount = reader.uint(1);
|
|
|
|
state.maxplayers = reader.uint(1);
|
2019-01-13 07:01:55 +01:00
|
|
|
state.raw.cpuSpeed = reader.uint(2);
|
2019-01-10 13:03:07 +01:00
|
|
|
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);
|
2018-03-18 06:54:56 +01:00
|
|
|
|
2019-01-10 13:03:07 +01:00
|
|
|
const teamFields = this.readFieldList(reader);
|
|
|
|
const playerFields = this.readFieldList(reader);
|
2018-03-18 06:54:56 +01:00
|
|
|
|
2019-01-10 13:03:07 +01:00
|
|
|
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;
|
2018-03-18 06:54:56 +01:00
|
|
|
}
|
2019-01-10 13:03:07 +01:00
|
|
|
state.raw.teams.push(teamInfo);
|
|
|
|
}
|
2018-03-18 06:54:56 +01:00
|
|
|
|
2019-01-10 13:03:07 +01:00
|
|
|
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);
|
2018-03-18 06:54:56 +01:00
|
|
|
|
2019-01-10 13:03:07 +01:00
|
|
|
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;
|
2018-03-18 06:54:56 +01:00
|
|
|
}
|
|
|
|
}
|
2019-01-10 13:03:07 +01:00
|
|
|
playerInfo[key] = value;
|
2018-03-18 06:54:56 +01:00
|
|
|
}
|
2019-01-10 13:03:07 +01:00
|
|
|
state.players.push(playerInfo);
|
|
|
|
}
|
2018-03-18 06:54:56 +01:00
|
|
|
}
|
|
|
|
readFieldList(reader) {
|
2018-03-18 07:23:01 +01:00
|
|
|
const str = this.readString(reader);
|
|
|
|
if (!str) return [];
|
|
|
|
return ('?'+str)
|
2018-03-18 06:54:56 +01:00
|
|
|
.split('\t')
|
2023-09-13 16:31:58 +02:00
|
|
|
.map((a) => a.substring(1).trim().toLowerCase())
|
2018-03-18 06:54:56 +01:00
|
|
|
.map((a) => a === 'team name' ? 'name' : a)
|
|
|
|
.map((a) => a === 'player name' ? 'name' : a);
|
|
|
|
}
|
2018-03-18 07:23:01 +01:00
|
|
|
readValues(reader) {
|
|
|
|
const str = this.readString(reader);
|
|
|
|
if (!str) return [];
|
|
|
|
return str
|
|
|
|
.split('\t')
|
|
|
|
.map((a) => a.trim());
|
|
|
|
}
|
2018-03-18 06:54:56 +01:00
|
|
|
readString(reader) {
|
2019-02-05 02:58:28 +01:00
|
|
|
return reader.pascalString(1);
|
2018-03-18 06:54:56 +01:00
|
|
|
}
|
|
|
|
}
|