2020-12-05 10:00:00 +00:00
|
|
|
import {
|
|
|
|
Plugin,
|
|
|
|
Configurable,
|
|
|
|
EventListener,
|
|
|
|
DependencyLoad
|
|
|
|
} from '@squeebot/core/lib/plugin';
|
|
|
|
|
2020-12-13 10:16:49 +00:00
|
|
|
import { IMessage, MessageResolver } from '@squeebot/core/lib/types';
|
2020-12-05 10:00:00 +00:00
|
|
|
|
2020-12-13 10:16:49 +00:00
|
|
|
import { query, QueryResult } from 'gamedig';
|
2020-12-05 10:00:00 +00:00
|
|
|
|
|
|
|
interface IMinecraftType {
|
|
|
|
vanilla: {
|
|
|
|
raw: {
|
2021-03-22 19:55:53 +00:00
|
|
|
description: any,
|
2020-12-05 10:00:00 +00:00
|
|
|
players: {
|
|
|
|
max: number,
|
|
|
|
online: number;
|
|
|
|
},
|
|
|
|
version: {
|
|
|
|
name: string;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-12-13 10:16:49 +00:00
|
|
|
interface ICommonResponse {
|
|
|
|
name: string;
|
|
|
|
connect: string;
|
|
|
|
description: string;
|
|
|
|
players: string[];
|
|
|
|
maxPlayers: number;
|
|
|
|
version: string;
|
|
|
|
}
|
|
|
|
|
2021-03-22 19:55:53 +00:00
|
|
|
/**
|
|
|
|
* Find a string from a random mash of objects..
|
|
|
|
* @param obj Object
|
|
|
|
* @returns found string or undefined
|
|
|
|
*/
|
|
|
|
function traverseFindString(obj: any): string | undefined {
|
|
|
|
if (typeof obj === 'string') {
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Array.isArray(obj)) {
|
|
|
|
obj = obj.map((v) => traverseFindString(v));
|
|
|
|
for (const p of obj) {
|
|
|
|
if (typeof p === 'string') {
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const k of Object.keys(obj)) {
|
|
|
|
const find = traverseFindString(obj[k]);
|
|
|
|
if (find) {
|
|
|
|
return find;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-13 10:16:49 +00:00
|
|
|
class Parsers {
|
|
|
|
public static parseMinecraftStatus(response: QueryResult): ICommonResponse | null {
|
|
|
|
const result: ICommonResponse = {
|
|
|
|
name: 'Minecraft',
|
|
|
|
connect: response.connect,
|
|
|
|
description: '',
|
|
|
|
players: [],
|
|
|
|
maxPlayers: 0,
|
|
|
|
version: ''
|
|
|
|
};
|
|
|
|
|
|
|
|
result.players = response.players.map((player) => player.name) as string[];
|
|
|
|
const raw = response.raw as IMinecraftType;
|
|
|
|
if (!raw) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2021-03-22 19:55:53 +00:00
|
|
|
const desc = traverseFindString(raw.vanilla.raw.description) || '';
|
|
|
|
result.description = desc.replace(/§./g, '').replace(/\n/g, ' ');
|
2020-12-13 10:16:49 +00:00
|
|
|
|
|
|
|
result.maxPlayers = response.maxplayers;
|
|
|
|
result.version = raw.vanilla.raw.version.name;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-05 10:00:00 +00:00
|
|
|
@Configurable({
|
|
|
|
games: []
|
|
|
|
})
|
|
|
|
class GamePlugin extends Plugin {
|
|
|
|
@EventListener('pluginUnload')
|
|
|
|
public unloadEventHandler(plugin: string | Plugin): void {
|
|
|
|
if (plugin === this.name || plugin === this) {
|
|
|
|
this.emit('pluginUnloaded', this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@DependencyLoad('simplecommands')
|
|
|
|
addCommands(cmd: any): void {
|
|
|
|
for (const i in this.config.get('games', [])) {
|
|
|
|
const game = this.config.get('games', [])[i];
|
|
|
|
if (game.game === 'minecraft' && game.host) {
|
|
|
|
const port = game.port || 25565;
|
|
|
|
const command: any = {
|
|
|
|
plugin: this.name,
|
|
|
|
name: 'minecraft',
|
2020-12-13 10:16:49 +00:00
|
|
|
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
|
2020-12-05 10:00:00 +00:00
|
|
|
const keys: any[] = [];
|
|
|
|
let inclPlayers = false;
|
|
|
|
if (simplified[0] === 'players' || simplified[0] === 'online') {
|
|
|
|
inclPlayers = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
keys.push(['field', 'Minecraft', { type: 'title' }]);
|
|
|
|
|
|
|
|
let state;
|
2020-12-13 10:16:49 +00:00
|
|
|
let parsed;
|
2020-12-05 10:00:00 +00:00
|
|
|
try {
|
|
|
|
state = await query({
|
|
|
|
type: 'minecraftping',
|
|
|
|
host: game.host,
|
|
|
|
port,
|
|
|
|
});
|
2020-12-13 10:16:49 +00:00
|
|
|
|
|
|
|
parsed = Parsers.parseMinecraftStatus(state);
|
|
|
|
|
|
|
|
if (!state || !parsed) {
|
2020-12-05 10:00:00 +00:00
|
|
|
throw new Error();
|
|
|
|
}
|
|
|
|
} catch (e) {
|
2021-03-22 19:55:53 +00:00
|
|
|
console.log(e)
|
2020-12-05 10:00:00 +00:00
|
|
|
msg.resolve([['field', 'Server is offline.', { type: 'title' }]]);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inclPlayers) {
|
2020-12-13 10:16:49 +00:00
|
|
|
keys.push(['field', parsed.players.length ?
|
|
|
|
parsed.players.join(', ') : 'No players', { label: 'Players online' }]);
|
2020-12-05 10:00:00 +00:00
|
|
|
msg.resolve(keys);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-12-13 10:16:49 +00:00
|
|
|
keys.push(['field', parsed.connect, { label: 'Address' }]);
|
|
|
|
keys.push(['field', parsed.description, { label: 'MOTD', type: 'description' }]);
|
|
|
|
keys.push(['field', parsed.players.length + '/' + parsed.maxPlayers, { label: 'Players' }]);
|
|
|
|
keys.push(['field', parsed.version, { label: 'Version' }]);
|
2020-12-05 10:00:00 +00:00
|
|
|
|
|
|
|
msg.resolve(keys);
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
description: 'Minecraft server',
|
|
|
|
usage: '[players]',
|
|
|
|
aliases: ['mc']
|
|
|
|
};
|
|
|
|
|
|
|
|
if (game.rooms) {
|
|
|
|
command.source = game.rooms;
|
|
|
|
}
|
|
|
|
cmd.registerCommand(command);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = GamePlugin;
|