mirror of
https://github.com/gamedig/node-gamedig.git
synced 2024-11-17 17:25:19 +01:00
Improve gamespy1 (3.0.3)
This commit is contained in:
parent
1b11a132b9
commit
e8f2c174fb
3 changed files with 98 additions and 62 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
### 3.0.3
|
||||||
|
* Greatly improve gamespy1 protocol, with additional error handling and xserverquery support.
|
||||||
|
|
||||||
### 3.0.2
|
### 3.0.2
|
||||||
* Fix player name extraction for Unreal Tournament (1999) and possibly
|
* Fix player name extraction for Unreal Tournament (1999) and possibly
|
||||||
other gamespy1 games.
|
other gamespy1 games.
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
],
|
],
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"author": "GameDig Contributors",
|
"author": "GameDig Contributors",
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/gamedig/node-gamedig.git"
|
"url": "https://github.com/gamedig/node-gamedig.git"
|
||||||
|
|
|
@ -1,5 +1,33 @@
|
||||||
const Core = require('./core');
|
const Core = require('./core');
|
||||||
|
|
||||||
|
const stringKeys = new Set([
|
||||||
|
'website',
|
||||||
|
'gametype',
|
||||||
|
'gamemode',
|
||||||
|
'player'
|
||||||
|
]);
|
||||||
|
|
||||||
|
function normalizeEntry([key,value]) {
|
||||||
|
key = key.toLowerCase();
|
||||||
|
const split = key.split('_');
|
||||||
|
let keyType;
|
||||||
|
if (split.length === 2 && !isNaN(parseInt(split[1]))) {
|
||||||
|
keyType = split[0];
|
||||||
|
} else {
|
||||||
|
keyType = key;
|
||||||
|
}
|
||||||
|
if (!stringKeys.has(keyType) && !keyType.includes('name')) {
|
||||||
|
if (value.toLowerCase() === 'true') {
|
||||||
|
value = true;
|
||||||
|
} else if (value.toLowerCase() === 'false') {
|
||||||
|
value = false;
|
||||||
|
} else if (!isNaN(parseInt(value))) {
|
||||||
|
value = parseInt(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [key,value];
|
||||||
|
}
|
||||||
|
|
||||||
class Gamespy1 extends Core {
|
class Gamespy1 extends Core {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
@ -8,41 +36,47 @@ class Gamespy1 extends Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(state) {
|
async run(state) {
|
||||||
{
|
const raw = await this.sendPacket('\\status\\xserverquery');
|
||||||
const data = await this.sendPacket('info');
|
// Convert all keys to lowercase and normalize value types
|
||||||
|
const data = Object.fromEntries(Object.entries(raw).map(entry => normalizeEntry(entry)));
|
||||||
state.raw = data;
|
state.raw = data;
|
||||||
if ('hostname' in state.raw) state.name = state.raw.hostname;
|
if ('hostname' in data) state.name = data.hostname;
|
||||||
if ('mapname' in state.raw) state.map = state.raw.mapname;
|
if ('mapname' in data) state.map = data.mapname;
|
||||||
if (this.trueTest(state.raw.password)) state.password = true;
|
if (this.trueTest(data.password)) state.password = true;
|
||||||
if ('maxplayers' in state.raw) state.maxplayers = parseInt(state.raw.maxplayers);
|
if ('maxplayers' in data) state.maxplayers = parseInt(data.maxplayers);
|
||||||
if ('hostport' in state.raw) state.gamePort = parseInt(state.raw.hostport);
|
if ('hostport' in data) state.gamePort = parseInt(data.hostport);
|
||||||
}
|
|
||||||
{
|
const teamOffByOne = data.gameid === 'bf1942';
|
||||||
const data = await this.sendPacket('rules');
|
|
||||||
state.raw.rules = data;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const data = await this.sendPacket('players');
|
|
||||||
const playersById = {};
|
const playersById = {};
|
||||||
const teamNamesById = {};
|
const teamNamesById = {};
|
||||||
for (const ident of Object.keys(data)) {
|
for (const ident of Object.keys(data)) {
|
||||||
const split = ident.split('_');
|
const split = ident.split('_');
|
||||||
let key = split[0];
|
if (split.length !== 2) continue;
|
||||||
const id = split[1];
|
let key = split[0].toLowerCase();
|
||||||
|
const id = parseInt(split[1]);
|
||||||
|
if (isNaN(id)) continue;
|
||||||
let value = data[ident];
|
let value = data[ident];
|
||||||
|
|
||||||
|
delete data[ident];
|
||||||
|
|
||||||
|
if (key !== 'team' && key.startsWith('team')) {
|
||||||
|
// Info about a team
|
||||||
if (key === 'teamname') {
|
if (key === 'teamname') {
|
||||||
teamNamesById[id] = value;
|
teamNamesById[id] = value;
|
||||||
} else {
|
} else {
|
||||||
|
// other team info which we don't track
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Info about a player
|
||||||
if (!(id in playersById)) playersById[id] = {};
|
if (!(id in playersById)) playersById[id] = {};
|
||||||
if (key === 'playername') {
|
if (key === 'playername' || key === 'player') {
|
||||||
key = 'name';
|
key = 'name';
|
||||||
} else if (key === 'player') {
|
}
|
||||||
key = 'name';
|
if (key === 'team' && !isNaN(parseInt(value))) {
|
||||||
} else if (key === 'team' && !isNaN(parseInt(value))) {
|
|
||||||
key = 'teamId';
|
key = 'teamId';
|
||||||
value = parseInt(value);
|
value = parseInt(value) + (teamOffByOne ? -1 : 0);
|
||||||
} else if (key === 'score' || key === 'ping' || key === 'deaths' || key === 'kills' || key === 'frags') {
|
}
|
||||||
|
if (key !== 'name' && !isNaN(parseInt(value))) {
|
||||||
value = parseInt(value);
|
value = parseInt(value);
|
||||||
}
|
}
|
||||||
playersById[id][key] = value;
|
playersById[id][key] = value;
|
||||||
|
@ -68,7 +102,7 @@ class Gamespy1 extends Core {
|
||||||
// Convert player's team ID to team name if possible
|
// Convert player's team ID to team name if possible
|
||||||
if (player.hasOwnProperty('teamId')) {
|
if (player.hasOwnProperty('teamId')) {
|
||||||
if (Object.keys(teamNamesById).length) {
|
if (Object.keys(teamNamesById).length) {
|
||||||
player.team = teamNamesById[player.teamId - 1] || '';
|
player.team = teamNamesById[player.teamId] || '';
|
||||||
} else {
|
} else {
|
||||||
player.team = player.teamId;
|
player.team = player.teamId;
|
||||||
delete player.teamId;
|
delete player.teamId;
|
||||||
|
@ -78,7 +112,6 @@ class Gamespy1 extends Core {
|
||||||
state.players.push(player);
|
state.players.push(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async sendPacket(type) {
|
async sendPacket(type) {
|
||||||
let receivedQueryId;
|
let receivedQueryId;
|
||||||
|
@ -86,7 +119,7 @@ class Gamespy1 extends Core {
|
||||||
const parts = new Set();
|
const parts = new Set();
|
||||||
let maxPartNum = 0;
|
let maxPartNum = 0;
|
||||||
|
|
||||||
return await this.udpSend('\\'+type+'\\', buffer => {
|
return await this.udpSend(type, buffer => {
|
||||||
const reader = this.reader(buffer);
|
const reader = this.reader(buffer);
|
||||||
const str = reader.string(buffer.length);
|
const str = reader.string(buffer.length);
|
||||||
const split = str.split('\\');
|
const split = str.split('\\');
|
||||||
|
|
Loading…
Reference in a new issue