diff --git a/bot.js b/bot.js new file mode 100644 index 0000000..25a2428 --- /dev/null +++ b/bot.js @@ -0,0 +1,194 @@ +/* eslint-disable max-len */ + +const mc = require('minecraft-protocol'); +const crypto = require('crypto'); +const colorConvert = require('color-convert'); +const sleep = require('sleep-promise'); +const generateEaglerUsername = require('./util/generateEaglerUsername'); +const {EventEmitter} = require('events'); +const {loadPlugins} = require('./util/loadPlugins'); +const uuid = require('uuid-by-string'); +const readline = require('node:readline'); +const {stdin: input, stdout: output} = require('node:process'); +const rl = readline.createInterface({input, output}); +const moment = require('moment-timezone'); +const cowsay = require('cowsay2'); +const cows = require('cowsay2/cows'); +const util = require('node:util'); +const {VM} = require('vm2'); +const randomstring = require('randomstring'); +const mineflayer = require('mineflayer'); + +/** + * makes the bot + * @param {Object} server the server object used in the config + * @param {Object} config the config file + * @param {Array} bots bots array (used in index.js, look in there) + * @param {Class} dcclient discord client + */ +async function createBot(server, config, bots, dcclient) { + const bot = new EventEmitter(); + bot.options = { + username: /* process.argv[2] */ server.host === 'mc.chomens41793.ga' ? + 'ChomeNS_Bot' : + randomstring.generate(16), + host: /* process.argv[2] */ server.host, + port: /* process.argv[3] ? Number(process.argv[3]) : 25565*/ server.port, + version: config.version, + checkTimeoutInterval: '30000', + keepAlive: false, + hideErrors: true, + }; + bot._client = mc.createClient(bot.options); + bot.version = bot._client.version; + bot.write = (name, data) => bot._client.write(name, data); + bot.end = (reason = 'end') => { + bot.emit('end', reason); + bot.removeAllListeners(); + bot._client.end(); + bot._client.removeAllListeners(); + }; + bot.visibility = false; + bot.getplayerusername = {}; + if (typeof bot.messageLogging === 'undefined') bot.messageLogging = true; + + await sleep(200); + + loadPlugins(bot, dcclient, config, rl); + + bot.getBots = () => bots; + bots.push(bot); + + const channel = dcclient.channels.cache.get(config.discord.servers[bot.options.host]); + + bot.playersAddedPlayers = {}; + bot.getplayerusername = {}; + + bot._client.on('login', async function(data) { + bot.entityId = data.entityId; + bot.uuid = bot._client.uuid; + bot.username = bot._client.username; + chatMessage = require('prismarine-chat')(bot.version); + const mcData = require('minecraft-data')(bot.version); + bot.console.info( + `Successfully logged in to: ${bot.options.host}:${bot.options.port}`, + ); + channel.send( + `Successfully logged in to: \`${bot.options.host}:${bot.options.port}\``, + ); + bot.eaglercrashstarted = false; + // await sleep(1500); + // bot.createCore(); + + bot.vmoptions = { + timeout: 2000, + sandbox: { + run: function(cmd) { + bot.core.run(cmd); + }, + mc, + mineflayer, + chat: bot.chat, + moment, + randomstring, + uuid, + chatMessage, + crypto, + colorConvert, + bruhifyText: function(message) { + if ( + typeof message !== 'string' + ) throw new SyntaxError('message must be a string'); + bot.bruhifyText = message.substring(0, 1000); + }, + generateEaglerUsername, + cowsay, + cows, + mcData, + }, + }; + bot.vm = new VM(bot.vmoptions); + + // await sleep(1400); + // bot.tellraw('@a', [ + // { + // text: 'ChomeNS Bot', + // color: 'yellow', + // }, + // { + // text: ' - ', + // color: 'dark_gray', + // }, + // { + // text: 'made by ', + // color: 'gray', + // }, + // { + // text: 'chayapak', + // color: 'gold', + // }, + // ]); + }); + + bot.on('player_added', (player) => { + bot.playersAddedPlayers[player.name] = player.UUID; + bot.getplayerusername[player.UUID] = player.name; + }); + + bot._client.on('end', function(reason) { + bot.emit('end', reason, 'end'); + }); + + bot.once('end', (reason, event) => { + bot.console.info( + `Disconnected from ${bot.options.host} (${event} event): ${util.inspect(reason)}`, + ); + channel.send(`Disconnected: \`${util.inspect(reason)}\``); + + let timeout = config.reconnectTimeout; + + try { + if (reason.text) { + if (reason.text === + 'Wait 5 seconds before connecting, thanks! :)' || + reason.text === + 'You are logging in too fast, try again later.' + ) timeout = 1000 * 7; + } + } catch (e) { + bot.console.error(e); + } + + setTimeout(() => { + bot.end(); + createBot(server, config, bots, dcclient); + }, timeout); + }); + + bot._client.on('keep_alive', (packet) => { + bot.write('keep_alive', {keepAliveId: packet.keepAliveId}); + }); + bot._client.on('game_state_change', () => { + bot.write('client_command', {payload: 0}); + }); + + bot._client.on('kick_disconnect', function(data) { + const parsed = JSON.parse(data.reason); + bot.emit('end', parsed, 'kick_disconnect'); + }); + + bot._client.on('disconnect', function(data) { + const parsed = JSON.parse(data.reason); + bot.emit('end', parsed, 'disconnect'); + }); + + bot._client.on('error', function() {}); + + process.on('uncaughtException', (error) => { + console.error('uncaught ' + util.inspect(error)); + // channel.send('uncaught ```\n' + util.inspect(error) + '\n```'); + // bot.emit('end', 'uncaughtException', 'process: uncaughtException'); + }); +}; + +module.exports = {createBot}; diff --git a/index.js b/index.js index c209892..d1df6a1 100644 --- a/index.js +++ b/index.js @@ -3,25 +3,16 @@ /* eslint-disable prefer-rest-params */ /* eslint-disable no-tabs */ /* eslint-disable no-undef */ -const mc = require('minecraft-protocol'); const config = require('./config'); -const crypto = require('crypto'); -const colorConvert = require('color-convert'); -const sleep = require('sleep-promise'); -const generateEaglerUsername = require('./util/generateEaglerUsername'); -const {EventEmitter} = require('events'); -const {loadPlugins} = require('./util/loadPlugins'); -const uuid = require('uuid-by-string'); -const readline = require('node:readline'); -const {stdin: input, stdout: output} = require('node:process'); -const rl = readline.createInterface({input, output}); -const moment = require('moment-timezone'); -const cowsay = require('cowsay2'); -const cows = require('cowsay2/cows'); -const util = require('node:util'); -const {VM} = require('vm2'); -const randomstring = require('randomstring'); -const mineflayer = require('mineflayer'); +const {createBot} = require('./bot'); +const { + Client, + Intents, +} = require('discord.js'); +const intents = new Intents(['GUILDS', 'GUILD_MESSAGES']); +const dcclient = new Client({ + intents, +}); // readline > fix on console.log // const log = console.log; // console.log = function() { @@ -30,195 +21,12 @@ const mineflayer = require('mineflayer'); // rl._refreshLine(); // }; -// Load discord.js -const { - Client, - Intents, -} = require('discord.js'); -// Create Discord intentions, required in v13 -const intents = new Intents(['GUILDS', 'GUILD_MESSAGES']); -// Create Discord client -const dcclient = new Client({ - intents, -}); +const bots = []; -async function botThings() { - bot = new EventEmitter(); - bot.options = { - username: process.argv[2] === 'mc.chomens41793.ga' ? - 'ChomeNS_Bot' : - randomstring.generate(16), - host: process.argv[2], - port: process.argv[3] ? Number(process.argv[3]) : 25565, - version: config.version, - checkTimeoutInterval: '30000', - keepAlive: false, - hideErrors: true, - }; - bot._client = mc.createClient(bot.options); - bot.version = bot._client.version; - bot.write = (name, data) => bot._client.write(name, data); - bot.end = (reason = 'end') => { - bot.emit('end', reason); - bot.removeAllListeners(); - bot._client.end(); - bot._client.removeAllListeners(); - }; - bot.visibility = false; - bot.getplayerusername = {}; - if (typeof bot.messageLogging === 'undefined') bot.messageLogging = true; - - await sleep(500); - - loadPlugins(bot, dcclient, config, rl); -} - -/** - * Main bot function - */ -async function main() { - const channel = dcclient.channels.cache.get(config.discord.servers[process.argv[2]]); - - module.exports = bot; - - bot.playersAddedPlayers = {}; - bot.getplayerusername = {}; - - bot.once('end', (reason, event) => { - bot.console.info( - `Disconnected from ${bot.options.host} (${event} event): ${util.inspect(reason)}`, - ); - channel.send(`Disconnected: \`${util.inspect(reason)}\``); - - let timeout = config.reconnectTimeout; - - try { - if (reason.text) { - if (reason.text === - 'Wait 5 seconds before connecting, thanks! :)' || - reason.text === - 'You are logging in too fast, try again later.' - ) timeout = 1000 * 7; - } - } catch (e) { - bot.console.error(e); - } - - setTimeout(() => { - bot.end(); - botThings(); - main(); - }, timeout); +dcclient.on('ready', () => { + config.servers.forEach(async (server) => { + createBot(server, config, bots, dcclient); }); - - await sleep(1000); - - bot.console.info(`Connecting to: ${bot.options.host}:${bot.options.port}...`); - channel.send(`Connecting to: \`${bot.options.host}:${bot.options.port}\`...`); - bot._client.on('login', async function(data) { - bot.entityId = data.entityId; - bot.uuid = bot._client.uuid; - bot.username = bot._client.username; - chatMessage = require('prismarine-chat')(bot.version); - const mcData = require('minecraft-data')(bot.version); - bot.console.info( - `Successfully logged in to: ${bot.options.host}:${bot.options.port}`, - ); - channel.send( - `Successfully logged in to: \`${bot.options.host}:${bot.options.port}\``, - ); - bot.eaglercrashstarted = false; - await sleep(1500); - bot.createCore(); - - bot.vmoptions = { - timeout: 2000, - sandbox: { - run: function(cmd) { - bot.core.run(cmd); - }, - mc, - mineflayer, - chat: bot.chat, - moment, - randomstring, - uuid, - chatMessage, - crypto, - colorConvert, - bruhifyText: function(message) { - if ( - typeof message !== 'string' - ) throw new SyntaxError('message must be a string'); - bot.bruhifyText = message.substring(0, 1000); - }, - generateEaglerUsername, - cowsay, - cows, - mcData, - }, - }; - bot.vm = new VM(bot.vmoptions); - - await sleep(1400); - bot.tellraw('@a', [ - { - text: 'ChomeNS Bot', - color: 'yellow', - }, - { - text: ' - ', - color: 'dark_gray', - }, - { - text: 'made by ', - color: 'gray', - }, - { - text: 'chayapak', - color: 'gold', - }, - ]); - }); - - bot.on('player_added', (player) => { - bot.playersAddedPlayers[player.name] = player.UUID; - bot.getplayerusername[player.UUID] = player.name; - }); - - bot._client.on('end', function(reason) { - bot.emit('end', reason, 'end'); - }); - - bot._client.on('keep_alive', (packet) => { - bot.write('keep_alive', {keepAliveId: packet.keepAliveId}); - }); - bot._client.on('game_state_change', () => { - bot.write('client_command', {payload: 0}); - }); - - bot._client.on('kick_disconnect', function(data) { - const parsed = JSON.parse(data.reason); - bot.emit('end', parsed, 'kick_disconnect'); - }); - - bot._client.on('disconnect', function(data) { - const parsed = JSON.parse(data.reason); - bot.emit('end', parsed, 'disconnect'); - }); - - bot._client.on('error', function() {}); - - process.on('uncaughtException', (error) => { - console.error('uncaught ' + util.inspect(error)); - channel.send('uncaught ```\n' + util.inspect(error) + '\n```'); - bot.emit('end', 'uncaughtException', 'process: uncaughtException'); - }); -} - -dcclient.on('ready', async () => { - botThings(); - main(); }); dcclient.login(config.discord.token); diff --git a/plugins/console.js b/plugins/console.js index ec75f74..320dede 100644 --- a/plugins/console.js +++ b/plugins/console.js @@ -15,14 +15,15 @@ function inject(bot, dcclient, config, rl) { } bot.console = {}; + bot.console.host = 'all'; bot.console.log = function(message) { console.log(prefix('&6LOG', message)); }; bot.console.info = function(message) { console.log(prefix('&aINFO', message)); }; - bot.console.error = function(message) { - console.log(prefix('&cERROR', message)); + bot.console.error = function(error) { + console.log(prefix('&cERROR', typeof error === 'string' ? error : error.stack)); }; bot.consoleQueue = []; @@ -55,6 +56,8 @@ function inject(bot, dcclient, config, rl) { try { if (line.toLowerCase() === '' || line.toLowerCase().startsWith(' ')) return; + + if (bot.options.host !== bot.console.host && bot.console.host !== 'all') return; if (line.toLowerCase() === '.exit' || line.toLowerCase() === '.end') { bot.emit('end', 'end command'); return; @@ -86,6 +89,13 @@ function inject(bot, dcclient, config, rl) { return; } if (line === '.kill') process.exit(); + if (line.startsWith('.csvr ')) { + const host = line.substring(6); + bot.console.host = host; + bot.console.info(`Host set to: ${host}`); + return; + } + if (line.startsWith('.')) { return bot.command_handler.run( bot.username, diff --git a/plugins/core.js b/plugins/core.js index dbec4c5..2126576 100644 --- a/plugins/core.js +++ b/plugins/core.js @@ -9,143 +9,130 @@ const Vec3 = require('vec3'); const relativePosition = new Vec3(0, 0, 0); function inject(bot, dcclient, config) { - bot.createCore = (layers = config.core.layers) => { - const core = { - isCore(position) { - return position.x >= core.start.x && position.x <= core.end.x && position.y >= core.start.y && position.y <= core.end.y && position.z >= core.start.z && position.z <= core.end.z; - }, - run(command) { - try { - if (config.useChat && + const core = { + isCore(position) { + return position.x >= core.start.x && position.x <= core.end.x && position.y >= core.start.y && position.y <= core.end.y && position.z >= core.start.z && position.z <= core.end.z; + }, + run(command) { + try { + if (config.useChat && command.startsWith('minecraft:tellraw @a ') && !command.includes('Console') && !command.includes('Discord') - ) { - bot.chat(chatMessage.fromNotch(command.replace('minecraft:tellraw @a ', '')).toMotd().replaceAll('\xa7', '&')); - return; - } - - relativePosition.x++; - - if (relativePosition.x >= 16) { - relativePosition.x = 0; - relativePosition.y++; - } - - if (relativePosition.y >= layers) { - relativePosition.y = 0; - relativePosition.z++; - } - - if (relativePosition.z >= 16) { - relativePosition.z = 0; - } - - const impulseMode = bot.options.host === '0.tcp.ap.ngrok.io'; - - const location = { - x: core.start.x + relativePosition.x, - y: core.start.y + relativePosition.y, - z: core.start.z + relativePosition.z, - }; - - if (impulseMode) bot.write('update_command_block', {location, command: command.substring(0, 32767), mode: 0, flags: 0}); - bot.write('update_command_block', {location, command: command.substring(0, 32767), mode: impulseMode ? 2 : 1, flags: 0b100}); - } catch (e) { + ) { + bot.chat(chatMessage.fromNotch(command.replace('minecraft:tellraw @a ', '')).toMotd().replaceAll('\xa7', '&')); return; } - }, - async loopPlace() { - try { - const fillCommand = `/minecraft:fill ${core.start.x} ${core.start.y} ${core.start.z} ${core.end.x} ${core.end.y} ${core.end.z} command_block${config.core.customName ? `{CustomName:'${JSON.stringify(config.core.customName)}'}` : ''}`; - const location = {x: Math.floor(bot.position.x), y: Math.floor(bot.position.y) - 1, z: Math.floor(bot.position.z)}; - bot.write('set_creative_slot', { - slot: 36, - item: { - present: true, - itemId: mcData.itemsByName['repeating_command_block'].id, - itemCount: 64, - nbtData: nbt.comp({BlockEntityTag: nbt.comp({ - Command: nbt.string(fillCommand), - auto: nbt.byte(1), - TrackOutput: nbt.byte(0), - })}), - }, - }); - await sleep(50); - bot.write('block_dig', { - status: 0, - location, - face: 1, - }); - await sleep(50); - bot.write('block_place', { - location, - direction: 1, - hand: 0, - cursorX: 0.5, - cursorY: 0.5, - cursorZ: 0.5, - insideBlock: false, - }); - fillCore(); - } catch (e) {} - }, - // fillCore(useCore) { - // const fillCommand = `/minecraft:fill ${core.start.x} ${core.start.y} ${core.start.z} ${core.end.x} ${core.end.y} ${core.end.z} command_block{CustomName:'{"text":"ChomeNS Bot Core","color":"yellow"}'}`; - // if (useCore==true) { - // bot.core.run(fillCommand); - // } else { - // bot.chat(fillCommand); - // } - // bot.emit('core_filled'); - // }, - }; + relativePosition.x++; - bot._client.on('position', (position) => { - bot.position = position; + if (relativePosition.x >= 16) { + relativePosition.x = 0; + relativePosition.y++; + } - bot.emit('position', position); - }); + if (relativePosition.y >= config.core.layers) { + relativePosition.y = 0; + relativePosition.z++; + } - // bot._client.on('block_change', (packet) => { - // if (core.isCore(packet.location) && packet.type === 0) fillCore(); - // }); + if (relativePosition.z >= 16) { + relativePosition.z = 0; + } - // bot._client.on('multi_block_change', (packet) => { - // if (core.start === packet.chunkCoordinates || core.end === packet.chunkCoordinates) fillCore(); - // }); + const impulseMode = bot.options.host === '0.tcp.ap.ngrok.io'; - bot.on('end', () => { - clearInterval(interval); - }); + const location = { + x: core.start.x + relativePosition.x, + y: core.start.y + relativePosition.y, + z: core.start.z + relativePosition.z, + }; - fillCore(); + if (impulseMode) bot.write('update_command_block', {location, command: command.substring(0, 32767), mode: 0, flags: 0}); + bot.write('update_command_block', {location, command: command.substring(0, 32767), mode: impulseMode ? 2 : 1, flags: 0b100}); + } catch (e) { + bot.console.error(e); + } + }, + async loopPlace() { + try { + const fillCommand = `/minecraft:fill ${core.start.x} ${core.start.y} ${core.start.z} ${core.end.x} ${core.end.y} ${core.end.z} command_block${config.core.customName ? `{CustomName:'${JSON.stringify(config.core.customName)}'}` : ''}`; + const location = {x: Math.floor(bot.position.x), y: Math.floor(bot.position.y) - 1, z: Math.floor(bot.position.z)}; + bot.write('set_creative_slot', { + slot: 36, + item: { + present: true, + itemId: mcData.itemsByName['repeating_command_block'].id, + itemCount: 64, + nbtData: nbt.comp({BlockEntityTag: nbt.comp({ + Command: nbt.string(fillCommand), + auto: nbt.byte(1), + TrackOutput: nbt.byte(0), + })}), + }, + }); + await sleep(50); + bot.write('block_dig', { + status: 0, + location, + face: 1, + }); + await sleep(50); + bot.write('block_place', { + location, + direction: 1, + hand: 0, + cursorX: 0.5, + cursorY: 0.5, + cursorZ: 0.5, + insideBlock: false, + }); + } catch (e) { + bot.console.error(e); + } + }, + // fillCore(useCore) { + // const fillCommand = `/minecraft:fill ${core.start.x} ${core.start.y} ${core.start.z} ${core.end.x} ${core.end.y} ${core.end.z} command_block{CustomName:'{"text":"ChomeNS Bot Core","color":"yellow"}'}`; + // if (useCore==true) { + // bot.core.run(fillCommand); + // } else { + // bot.chat(fillCommand); + // } + // bot.emit('core_filled'); + // }, + }; - bot.core = core; + // bot._client.on('block_change', (packet) => { + // if (core.isCore(packet.location) && packet.type === 0) fillCore(); + // }); - function fillCore() { - core.start = new Vec3( - Math.floor(bot.position.x / 16) * 16, - 0 /* bot.position.y */, - Math.floor(bot.position.z / 16) * 16, - ).floor(); - core.end = core.start.clone().translate(16, layers, 16).subtract(new Vec3(1, 1, 1)); + // bot._client.on('multi_block_change', (packet) => { + // if (core.start === packet.chunkCoordinates || core.end === packet.chunkCoordinates) fillCore(); + // }); - // core.fillCore(); - } + bot.on('end', () => { + clearInterval(interval); + }); + + bot.core = core; + + function fillCore() { + core.start = new Vec3( + Math.floor(bot.position.x / 16) * 16, + 0 /* bot.position.y */, + Math.floor(bot.position.z / 16) * 16, + ).floor(); + core.end = core.start.clone().translate(16, config.core.layers, 16).subtract(new Vec3(1, 1, 1)); bot.core.loopPlace(); + // core.fillCore(); + } - bot.on('position', bot.core.loopPlace); + bot.on('position', fillCore); - const interval = setInterval(() => { - bot.core.loopPlace(); - }, config.core.refillInterval); - - return core; - }; + const interval = setInterval(() => { + bot.core.loopPlace(); + }, config.core.refillInterval); } module.exports = {inject}; diff --git a/plugins/position.js b/plugins/position.js index 3318648..498e367 100644 --- a/plugins/position.js +++ b/plugins/position.js @@ -1,12 +1,9 @@ /* eslint-disable require-jsdoc */ -const Vec3 = require('vec3'); - function inject(bot) { - bot.position = new Vec3(null, null, null); - bot._client.on('position', (position) => { - bot.position = new Vec3(position.x, position.y, position.z); + bot.position = position; bot.write('teleport_confirm', {teleportId: position.teleportId}); + bot.emit('position', position); }); }