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; } class Parsers { public static parseMinecraftStatus(response: QueryResult): ICommonResponse | null { const result: ICommonResponse = { name: 'Minecraft', connect: response.connect.endsWith(':25565') ? response.connect.split(':')[0] : 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; } result.description = response.name.replace(/[^\x00-\x7F]./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; const command: any = { plugin: this.name, name: 'minecraft', execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { 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) { 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;