Add eslint (#364)

* Add initial prettier and eslint configs

* Modify prettierrc

* Run eslint on everything

* Actually remove prettier

* Fix some eslints

* Remove label in gs2

* Update CHANGELOG

* Update eslintrc to specify es2021
This commit is contained in:
CosminPerRam 2023-09-19 19:52:35 +03:00 committed by GitHub
parent bff9507189
commit 93a9095d99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 6960 additions and 5211 deletions

View file

@ -1,140 +1,141 @@
import Core from './core.js';
export default class gamespy2 extends Core {
constructor() {
super();
this.encoding = 'latin1';
this.byteorder = 'be';
}
async run(state) {
// Parse info
{
const body = await this.sendPacket([0xff, 0, 0]);
const reader = this.reader(body);
while (!reader.done()) {
const key = reader.string();
const value = reader.string();
if (!key) break;
state.raw[key] = value;
}
if ('hostname' in state.raw) state.name = state.raw.hostname;
if ('mapname' in state.raw) state.map = state.raw.mapname;
if (this.trueTest(state.raw.password)) state.password = true;
if ('maxplayers' in state.raw) state.maxplayers = parseInt(state.raw.maxplayers);
if ('hostport' in state.raw) state.gamePort = parseInt(state.raw.hostport);
}
// Parse players
{
const body = await this.sendPacket([0, 0xff, 0]);
const reader = this.reader(body);
for (const rawPlayer of this.readFieldData(reader)) {
state.players.push(rawPlayer);
}
}
// Parse teams
{
const body = await this.sendPacket([0, 0, 0xff]);
const reader = this.reader(body);
state.raw.teams = this.readFieldData(reader);
}
// Special case for america's army 1 and 2
// both use gamename = "armygame"
if (state.raw.gamename === 'armygame') {
const stripColor = (str) => {
// uses unreal 2 color codes
return str.replace(/\x1b...|[\x00-\x1a]/g,'');
};
state.name = stripColor(state.name);
state.map = stripColor(state.map);
for(const key of Object.keys(state.raw)) {
if(typeof state.raw[key] === 'string') {
state.raw[key] = stripColor(state.raw[key]);
}
}
for(const player of state.players) {
if(!('name' in player)) continue;
player.name = stripColor(player.name);
}
}
}
async sendPacket(type) {
const request = Buffer.concat([
Buffer.from([0xfe,0xfd,0x00]), // gamespy2
Buffer.from([0x00,0x00,0x00,0x01]), // ping ID
Buffer.from(type)
]);
return await this.udpSend(request, buffer => {
const reader = this.reader(buffer);
const header = reader.uint(1);
if (header !== 0) return;
const pingId = reader.uint(4);
if (pingId !== 1) return;
return reader.rest();
});
}
readFieldData(reader) {
const zero = reader.uint(1); // always 0
const count = reader.uint(1); // number of rows in this data
// some games omit the count byte entirely if it's 0 or at random (like americas army)
// Luckily, count should always be <64, and ascii characters will typically be >64,
// so we can detect this.
if (count > 64) {
reader.skip(-1);
this.logger.debug("Detected missing count byte, rewinding by 1");
} else {
this.logger.debug("Detected row count: " + count);
}
this.logger.debug(() => "Reading fields, starting at: "+reader.rest());
const fields = [];
while(!reader.done()) {
let field = reader.string();
if(!field) break;
fields.push(field);
this.logger.debug("field:"+field);
}
if (!fields.length) return [];
const units = [];
outer: while(!reader.done()) {
const unit = {};
for(let iField = 0; iField < fields.length; iField++) {
let key = fields[iField];
let value = reader.string();
if(!value && iField === 0) break outer;
this.logger.debug("value:"+value);
if(key === 'player_') key = 'name';
else if(key === 'score_') key = 'score';
else if(key === 'deaths_') key = 'deaths';
else if(key === 'ping_') key = 'ping';
else if(key === 'team_') key = 'team';
else if(key === 'kills_') key = 'kills';
else if(key === 'team_t') key = 'name';
else if(key === 'tickets_t') key = 'tickets';
if(
key === 'score' || key === 'deaths'
|| key === 'ping' || key === 'team'
|| key === 'kills' || key === 'tickets'
) {
if(value === '') continue;
value = parseInt(value);
}
unit[key] = value;
}
units.push(unit);
}
return units;
}
}
import Core from './core.js'
export default class gamespy2 extends Core {
constructor () {
super()
this.encoding = 'latin1'
this.byteorder = 'be'
}
async run (state) {
// Parse info
{
const body = await this.sendPacket([0xff, 0, 0])
const reader = this.reader(body)
while (!reader.done()) {
const key = reader.string()
const value = reader.string()
if (!key) break
state.raw[key] = value
}
if ('hostname' in state.raw) state.name = state.raw.hostname
if ('mapname' in state.raw) state.map = state.raw.mapname
if (this.trueTest(state.raw.password)) state.password = true
if ('maxplayers' in state.raw) state.maxplayers = parseInt(state.raw.maxplayers)
if ('hostport' in state.raw) state.gamePort = parseInt(state.raw.hostport)
}
// Parse players
{
const body = await this.sendPacket([0, 0xff, 0])
const reader = this.reader(body)
for (const rawPlayer of this.readFieldData(reader)) {
state.players.push(rawPlayer)
}
}
// Parse teams
{
const body = await this.sendPacket([0, 0, 0xff])
const reader = this.reader(body)
state.raw.teams = this.readFieldData(reader)
}
// Special case for america's army 1 and 2
// both use gamename = "armygame"
if (state.raw.gamename === 'armygame') {
const stripColor = (str) => {
// uses unreal 2 color codes
return str.replace(/\x1b...|[\x00-\x1a]/g, '')
}
state.name = stripColor(state.name)
state.map = stripColor(state.map)
for (const key of Object.keys(state.raw)) {
if (typeof state.raw[key] === 'string') {
state.raw[key] = stripColor(state.raw[key])
}
}
for (const player of state.players) {
if (!('name' in player)) continue
player.name = stripColor(player.name)
}
}
}
async sendPacket (type) {
const request = Buffer.concat([
Buffer.from([0xfe, 0xfd, 0x00]), // gamespy2
Buffer.from([0x00, 0x00, 0x00, 0x01]), // ping ID
Buffer.from(type)
])
return await this.udpSend(request, buffer => {
const reader = this.reader(buffer)
const header = reader.uint(1)
if (header !== 0) return
const pingId = reader.uint(4)
if (pingId !== 1) return
return reader.rest()
})
}
readFieldData (reader) {
reader.uint(1) // always 0
const count = reader.uint(1) // number of rows in this data
// some games omit the count byte entirely if it's 0 or at random (like americas army)
// Luckily, count should always be <64, and ascii characters will typically be >64,
// so we can detect this.
if (count > 64) {
reader.skip(-1)
this.logger.debug('Detected missing count byte, rewinding by 1')
} else {
this.logger.debug('Detected row count: ' + count)
}
this.logger.debug(() => 'Reading fields, starting at: ' + reader.rest())
const fields = []
while (!reader.done()) {
const field = reader.string()
if (!field) break
fields.push(field)
this.logger.debug('field:' + field)
}
if (!fields.length) return []
const units = []
while (!reader.done()) {
const unit = {}
for (let iField = 0; iField < fields.length; iField++) {
let key = fields[iField]
let value = reader.string()
if (!value && iField === 0) return units
this.logger.debug('value:' + value)
if (key === 'player_') key = 'name'
else if (key === 'score_') key = 'score'
else if (key === 'deaths_') key = 'deaths'
else if (key === 'ping_') key = 'ping'
else if (key === 'team_') key = 'team'
else if (key === 'kills_') key = 'kills'
else if (key === 'team_t') key = 'name'
else if (key === 'tickets_t') key = 'tickets'
if (
key === 'score' || key === 'deaths' ||
key === 'ping' || key === 'team' ||
key === 'kills' || key === 'tickets'
) {
if (value === '') continue
value = parseInt(value)
}
unit[key] = value
}
units.push(unit)
}
return units
}
}