plugins-evert/gamedig/plugin.ts

172 lines
4.3 KiB
TypeScript

import {
Plugin,
Configurable,
EventListener,
DependencyLoad
} from '@squeebot/core/lib/plugin';
import { IMessage, MessageResolver } from '@squeebot/core/lib/types';
import { query, QueryResult } from 'gamedig';
interface IMinecraftType {
vanilla: {
raw: {
description: any,
players: {
max: number,
online: number;
},
version: {
name: string;
}
}
};
}
interface ICommonResponse {
name: string;
connect: string;
description: string;
players: string[];
maxPlayers: number;
version: string;
}
/**
* 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;
}
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;
}
const desc = traverseFindString(raw.vanilla.raw.description) || '';
result.description = desc.replace(/§./g, '').replace(/\n/g, ' ');
result.maxPlayers = response.maxplayers;
result.version = raw.vanilla.raw.version.name;
return result;
}
}
@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',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
const keys: any[] = [];
let inclPlayers = false;
if (simplified[0] === 'players' || simplified[0] === 'online') {
inclPlayers = true;
}
keys.push(['field', 'Minecraft', { type: 'title' }]);
let state;
let parsed;
try {
state = await query({
type: 'minecraftping',
host: game.host,
port,
});
parsed = Parsers.parseMinecraftStatus(state);
if (!state || !parsed) {
throw new Error();
}
} catch (e) {
console.log(e)
msg.resolve([['field', 'Server is offline.', { type: 'title' }]]);
return true;
}
if (inclPlayers) {
keys.push(['field', parsed.players.length ?
parsed.players.join(', ') : 'No players', { label: 'Players online' }]);
msg.resolve(keys);
return true;
}
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' }]);
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;