command refactor & improvements

This commit is contained in:
Chipmunk 2024-04-02 17:53:10 -04:00
parent 5f3560910b
commit d3e576f7b9
69 changed files with 1267 additions and 1065 deletions

8
bot.js
View file

@ -16,9 +16,9 @@ function createBot (options = {}) {
options.prefix ??= '!'
options.brand ??= 'vanilla' // found that mineflayer has this so i added it here lol
options.colors ??= {}
options.colors.primary ??= 'white'
options.colors.secondary ??= 'green'
options.styles ??= {}
options.styles.primary ??= { color: 'white' }
options.styles.secondary ??= { color: 'green' }
options.autoReconnect ??= false
options.randomizeUsername ??= false
@ -48,7 +48,7 @@ function createBot (options = {}) {
bot.prefix = options.prefix
bot.brand = options.brand
bot.colors = options.colors
bot.styles = options.styles
bot.autoReconnect = options.autoReconnect
bot.randomizeUsername = options.randomizeUsername
bot['online-mode'] = options['online-mode']

View file

@ -1,23 +0,0 @@
const name = 'badapple'
const description = 'Plays a badapple video.'
const usages = ['[stop]']
const aliases = ['badapple']
const enabled = true
const permLevel = 0
function execute (bot, cmd, player, args) {
if (args[0] === 'stop') {
bot.video.stop()
bot.music.skip()
return
}
bot.video.summon(player.UUID, (uuids) => {
bot.music.stop()
bot.music.queue.push('./music/badapple.mid')
bot.video.play('./videos/badapple.txt', uuids)
})
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,47 +0,0 @@
const name = 'blacklist'
const description = 'idk'
const usages = [
'add <pattern> <flags>',
'remove <pattern> <flags>',
'list'
]
const aliases = ['blacklist']
const enabled = true
const permLevel = 1
function execute (bot, cmd, player, args, handler) {
const subCmd = args.shift()
let i, msg
switch (subCmd) {
case 'add':
bot.blacklist.push([args[0], args[1]])
bot.core.run(`minecraft:tellraw @a ${JSON.stringify([
{ text: 'Added regex ', color: bot.colors.primary },
{ text: `/${args[0]}/${args[1]}`, color: bot.colors.secondary },
' to the blacklist.'
])}`)
break
case 'remove':
i = bot.blacklist.indexOf([args[0], args[1]])
if (i < 0) throw new Error(`There is no regex /${args[0]}/${args[1]} in the blacklist.`)
bot.blacklist.splice(i, 1)
bot.core.run(`minecraft:tellraw @a ${JSON.stringify([
{ text: 'Removed regex ', color: bot.colors.primary },
{ text: `/${args[0]}/${args[1]}`, color: bot.colors.secondary },
' from the blacklist.'
])}`)
break
case 'list':
msg = [{ text: 'Regexes:\n', color: bot.colors.primary }]
bot.blacklist.forEach(([pattern, flags]) => {
msg.push({ text: `/${pattern}/${flags}\n`, color: bot.colors.secondary })
})
msg[msg.length - 1].text = msg[msg.length - 1].text.slice(0, -1)
bot.core.run(`minecraft:tellraw @a ${JSON.stringify(msg)}`)
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,42 +1,51 @@
const name = 'bruhify'
const description = 'recyclebot'
const usages = ['<text>']
const aliases = ['bruhify']
const enabled = true
const permLevel = 0
let isBruhifying = false
const { literal, argument, greedyString } = require('brigadier-commands')
const colorsys = require('colorsys')
function execute (bot, cmd, player, args, handler) {
if (isBruhifying) throw new Error('The bot is already bruhifying text!')
isBruhifying = true
module.exports = {
isBruhifying: false,
const message = args.join(' ')
register (dispatcher) {
const node = dispatcher.register(
literal('bruhify')
.then(
argument('message', greedyString())
.executes(this.bruhifyCommand.bind(this))
)
)
const lines = []
let j = 0
for (let i = 0; i < message.length; i++) {
const result = []
let hue = j
message.split('').forEach((char) => {
result.push({ text: char, color: colorsys.hsv2Hex(hue, 100, 100) })
hue += 355 / Math.max(message.length, 20)
})
node.description = 'recyclebot'
node.permissionLevel = 0
},
lines.push(JSON.stringify([{ text: '▚ ', color: 'light_purple' }].concat(result, [' ▚'])))
j += 355 / Math.max(message.length, 20)
}
bruhifyCommand (context) {
if (this.isBruhifying) throw new Error('The bot is already bruhifying text!')
this.isBruhifying = true
let k = 0
const interval = setInterval(() => {
bot.core.run(`minecraft:tellraw @a ${lines[k]}`)
if (++k > lines.length) {
clearInterval(interval)
isBruhifying = false
const source = context.source
const bot = source.bot
const message = context.getArgument('message')
const lines = []
let j = 0
for (let i = 0; i < message.length; i++) {
const result = []
let hue = j
message.split('').forEach((char) => {
result.push({ text: char, color: colorsys.hsv2Hex(hue, 100, 100) })
hue += 355 / Math.max(message.length, 20)
})
lines.push([{ text: '▚ ', color: 'light_purple' }].concat(result, [' ▚']))
j += 355 / Math.max(message.length, 20)
}
}, 50)
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }
let k = 0
const interval = setInterval(() => {
source.sendFeedback(lines[k], false)
if (++k >= lines.length) {
clearInterval(interval)
this.isBruhifying = false
}
}, 50)
}
}

View file

@ -1,13 +1,21 @@
const name = 'cb'
const description = 'Runs a command in the command core'
const usages = ['<command...>']
const aliases = ['cb']
const enabled = true
const { literal, argument, greedyString } = require('brigadier-commands')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('cb')
.then(
argument('command', greedyString())
.executes(this.runCommand)
)
)
function execute (bot, cmd, player, args) {
bot.core.run(args.join(' '))
node.description = 'Runs a command in the command core'
node.permissionLevel = 0
},
runCommand (context) {
const bot = context.source.bot
bot.core.run(context.getArgument('command'))
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,19 +1,33 @@
const name = 'clearchat'
const description = 'Clears the chat'
const usages = ['[selector]']
const aliases = ['clearchat', 'cc']
const enabled = true
const { literal, argument, greedyString } = require('brigadier-commands')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('clearchat')
.executes(this.clearChatCommand.bind(this))
.then(
argument('targets', greedyString())
.executes(this.targettedclearChatCommand.bind(this))
)
)
function execute (bot, cmd, player, args, handler) {
const text = []
while (text.length < 100) {
text.push('\n')
dispatcher.register(literal('cc').executes(this.clearChatCommand.bind(this)).redirect(node))
node.description = 'Clears the chat of everyone or a specific player'
node.permissionLevel = 0
},
clearChatCommand (context) {
const bot = context.source.bot
this.sendclearChatCommandMessage(bot, '@a')
},
targettedclearChatCommand (context) {
const bot = context.source.bot
this.sendclearChatCommandMessage(bot, context.getArgument('targets'))
},
sendclearChatCommandMessage (bot, targets) {
bot.tellraw({ text: '\n'.repeat(100) + 'The chat has been cleared', color: 'dark_green' }, targets)
}
text.push({ text: 'The chat has been cleared', color: 'dark_green' })
bot.core.run(`/minecraft:tellraw ${args.join(' ') || '@a'} ${JSON.stringify(text)}`)
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,66 +1,110 @@
const name = 'client'
const description = 'Creates and manages clients using minecraft-protocol.'
const usages = ['create <options (json)>', 'end <i>', 'write <i> <name> <data (json)>', 'list']
const aliases = ['client']
const enabled = true
const permLevel = 0
const { literal, argument, string, DynamicCommandExceptionType } = require('brigadier-commands')
const { json } = require('../util/command/argument/json')
const TextMessage = require('../util/command/text_message')
const mc = require('minecraft-protocol')
const clients = []
const sectionRegex = /\u00a7.?/g
const util = require('util')
function execute (bot, cmd, player, args, handler) {
const subCmd = args.shift()
const UNKNOWN_CLIENT_ERROR = new DynamicCommandExceptionType(string => new TextMessage(['Unknown client: ', string]))
switch (subCmd) {
case 'create': {
const options = { host: bot.host, port: bot.port, ...JSON.parse(args.join(' ').replace(sectionRegex, '')) }
module.exports = {
clients: [],
const client = mc.createClient(options)
const idx = clients.length
register (dispatcher) {
const node = dispatcher.register(
literal('client')
.then(
literal('create')
.then(
argument('options', json())
.executes(this.createCommand.bind(this))
)
)
.then(
literal('write')
.then(
argument('client', string())
.then(
argument('name', string())
.then(
argument('data', json())
.executes(this.writeCommand.bind(this))
)
)
)
)
.then(
literal('end')
.then(
argument('client', string())
.executes(this.endCommand.bind(this))
)
)
.then(
literal('list')
.executes(this.listCommand.bind(this))
)
)
client.once('login', () => bot.core.run('minecraft:tellraw @a ' + JSON.stringify([{ text: client.username, color: bot.colors.primary }, ' logged in'])))
node.description = 'Creates and manages this.clients using minecraft-protocol'
node.permissionLevel = 0
},
client.on('end', () => {
clients.splice(idx, 1)
bot.core.run('minecraft:tellraw @a ' + JSON.stringify([{ text: client.username, color: bot.colors.primary }, ' ended']))
})
createCommand (context) {
const source = context.source
const bot = source.bot
client.on('error', (err) => bot.core.run('minecraft:tellraw @a ' + JSON.stringify({ text: util.inspect(err).replace(/\n.*/g, ''), color: bot.colors.error })))
const options = { host: bot.host, port: bot.port, ...context.getArgument('options') }
clients.push(client)
}
break
case 'end': {
const stridx = args.join(' ').replace(sectionRegex, '')
let idx = Number(stridx)
if (!Number.isInteger(idx)) clients.forEach((client, cidx) => { if (client.username === stridx) idx = cidx })
if (!Number.isInteger(idx)) throw new Error('Unknown client: ' + stridx)
const client = mc.createClient(options)
const idx = this.clients.length
clients[idx].end()
clients.splice(idx, 1)
}
break
case 'write': {
const stridx = args.shift().replace(sectionRegex, '')
let idx = Number(stridx)
if (!Number.isInteger(idx)) clients.forEach((client, cidx) => { if (client.username === stridx) idx = cidx })
if (!Number.isInteger(idx)) throw new Error('Unknown client: ' + stridx)
client.once('login', () => source.sendFeedback([{ text: client.username, ...bot.styles.primary }, ' logged in']), false)
const name = args.shift()
const data = JSON.parse(args.join(' ').replace(sectionRegex, ''))
client.on('end', () => {
this.clients.splice(idx, 1)
source.sendFeedback([{ text: client.username, ...bot.styles.primary }, ' ended'], false)
})
clients[idx].write(name, data)
}
break
case 'list':
bot.core.run('minecraft:tellraw @a ' + JSON.stringify({ text: 'Clients: ' + clients.map(client => client.username).join('\u00a7r, '), color: bot.colors.primary }))
break
default:
throw new Error('Invalid or missing argument')
client.on('error', (err) => bot.tellraw({ text: err.toString(), ...bot.styles.error }, '@a'))
this.clients.push(client)
},
writeCommand (context) {
const idx = this.findClientIdxByString(context.getArgument('client'))
const name = context.getArgument('name')
const data = context.getArgument('data')
this.clients[idx].write(name, data)
},
endCommand (context) {
const source = context.source
const idx = this.findClientIdxByString(context.getArgument('client'))
this.clients[idx].end()
this.clients.splice(idx, 1)
},
listCommand (context) {
const source = context.source
const bot = source.bot
const list = []
for (let i = 0; i < this.clients.length; i++) {
const client = this.clients[i]
if (i !== 0) list.push(', ')
list.push(client.username)
}
source.sendFeedback([{ text: 'Clients: ', ...bot.styles.primary }, list], false)
},
findClientIdxByString (string) {
let idx = Number(string)
if (!this.clients[idx]) this.clients.forEach((client, cidx) => { if (client.username === string) idx = cidx })
if (!this.clients[idx]) throw UNKNOWN_CLIENT_ERROR.create(string)
return idx
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,49 +1,92 @@
const name = 'cloop'
const description = 'Loops commands'
const usages = [
'add <command...>',
'remove <index>',
'list'
]
const aliases = ['cloop']
const enabled = true
const { literal, argument, integer, greedyString } = require('brigadier-commands')
const permLevel = 1
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('cloop')
.requires(source => source.permissionLevel >= node.permissionLevel)
.then(
literal('add')
.then(
argument('interval', integer())
.then(
argument('command', greedyString())
.executes(this.addCommand)
)
)
)
.then(
literal('remove')
.then(
argument('index', integer())
.executes(this.removeCommand)
)
)
.then(
literal('list')
.executes(this.listCommand)
)
.then(
literal('clear')
.executes(this.clearCommand)
)
)
function execute (bot, cmd, player, args, handler) {
const subCommand = args.shift()
node.description = 'Loops commands in the command core'
node.permissionLevel = 1
},
let interval, command, i, msg
switch (subCommand) {
case 'add':
interval = parseFloat(args.shift())
command = args.join(' ').replace(/u00a7.?/g, '')
bot.cloops.push({ command, interval })
addCommand (context) {
const source = context.source
const bot = source.bot
bot.core.run(`/tellraw @a ${JSON.stringify([
{ text: 'Added command ', color: bot.colors.primary },
{ text: command, color: bot.colors.secondary },
' to cloops.'
])}`)
break
case 'remove':
i = parseFloat(args.shift())
bot.cloops.splice(i, 1)
const interval = context.getArgument('interval')
const command = context.getArgument('command')
bot.cloops.push({ command, interval })
bot.core.run(`/tellraw @a ${JSON.stringify([
{ text: 'Removed cloop ', color: bot.colors.primary },
{ text: i, color: bot.colors.secondary },
'.'
])}`)
break
case 'list':
msg = [{ text: 'Cloops: \n', color: bot.colors.primary }]
for (const i in bot.cloops) {
msg.push({ text: `${i}: ` })
msg.push({ text: `${bot.cloops[i].command}\n`, color: bot.colors.secondary })
}
bot.core.run(`/tellraw @a ${JSON.stringify(msg)}`)
source.sendFeedback([
{ text: 'Looping command ', ...bot.styles.primary },
{ text: command, ...bot.styles.secondary },
' at interval ',
{ text: String(interval), ...bot.styles.secondary }
], false)
},
removeCommand (context) {
const source = context.source
const bot = source.bot
const idx = context.getArgument('index')
bot.cloops.splice(idx, 1)
source.sendFeedback([
{ text: 'Removed cloop ', ...bot.styles.primary },
{ text: String(idx), ...bot.styles.secondary }
], false)
},
listCommand (context) {
const source = context.source
const bot = source.bot
const msg = [{ text: 'Cloops: \n', ...bot.styles.primary }]
for (let i = 0; i < bot.cloops.length; i++) {
if (i !== 0) msg.push('\n')
msg.push(
String(i),
': ',
{ text: String(bot.cloops[i].command), ...bot.styles.secondary }
)
}
source.sendFeedback(msg, false)
},
clearCommand (context) {
const source = context.source
const bot = source.bot
bot.cloops.splice(0, bot.cloops.length)
source.sendFeedback({ text: 'Cleared cloops', ...bot.styles.primary }, false)
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,16 +0,0 @@
const name = 'consoleserver'
const description = 'sets the console server'
const usages = ['<host...>']
const aliases = ['consoleserver', 'consolesvr', 'csvr']
const enabled = false
const permLevel = 0
function execute (bot, cmd, player, args) {
const host = args.join(' ')
bot.getBots().forEach(bot => {
bot.console.host = host
})
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,13 +0,0 @@
const name = 'crashmf'
const description = 'Crashes mineflayer bots.'
const usage = '{prefix}crashmf'
const aliases = ['crashmf']
const enabled = true
const permLevel = 0
function execute (bot, cmd, entity, args, handler) {
bot.core.run(`/tellraw @a ${JSON.stringify({ translate: 'translation.test.invalid', with: ['amogeese'] })}`)
}
module.exports = { name, description, usage, aliases, enabled, execute, permLevel }

View file

@ -1,37 +1,43 @@
const name = 'credits'
const description = 'Shows bot credits.'
const usages = []
const aliases = ['credits']
const enabled = true
const { literal } = require('brigadier-commands')
const pkg = require('../package.json')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('credits')
.executes(this.creditsCommand)
)
const pack = require('./../package.json')
node.description = 'Lists people who have contributed to the bot'
node.permissionLevel = 0
},
function execute (bot, cmd, entity, args, handler) {
bot.core.run(`/tellraw @a ${JSON.stringify([
{ text: '', color: 'gray' },
{ text: 'Credits\n', color: bot.colors.primary, bold: true },
creditsCommand (context) {
const source = context.source
const bot = source.bot
{ text: '_ChipMC_', color: 'blue' },
' - creating the bot\n',
source.sendFeedback([
{ text: '', color: 'gray' },
{ text: 'Credits\n', ...bot.styles.primary, bold: true },
{ text: 'hhhzzzsss', color: 'aqua', bold: true },
' and ',
{ text: 'eva', color: 'light_purple', italic: true },
' - creating the midi converter.\n',
{ text: '_ChipMC_', color: 'blue' },
' - creating the bot\n',
{ text: 'ma', color: 'aqua' },
{ text: 'ni', color: 'light_purple' },
{ text: 'a', color: 'white' },
{ text: 'pl', color: 'light_purple' },
{ text: 'ay', color: 'aqua' },
' and ',
{ text: 'ayunami2000', color: 'red' },
' - creating the image converter',
{ text: 'hhhzzzsss', color: 'aqua', bold: true },
' and ',
{ text: 'eva', color: 'light_purple', italic: true },
' - creating the midi converter.\n',
`\n\nDependencies: ${Object.entries(pack.dependencies).join(' ')}`
])}`)
{ text: 'ma', color: 'aqua' },
{ text: 'ni', color: 'light_purple' },
{ text: 'a', color: 'white' },
{ text: 'pl', color: 'light_purple' },
{ text: 'ay', color: 'aqua' },
' and ',
{ text: 'ayunami2000', color: 'red' },
' - creating the image converter',
'\n\nDependencies: ' + Object.entries(pkg.dependencies).map(entry => entry.join(' ')).join(', ')
], false)
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

25
commands/csvr.js Normal file
View file

@ -0,0 +1,25 @@
const { literal, argument, greedyString } = require('brigadier-commands')
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('csvr')
.then(
argument('host', greedyString())
.executes(this.consoleServerCommand)
)
)
node.description = 'Sets the console server'
node.permissionLevel = 0
},
consoleServerCommand (context) {
const bot = context.source.bot
const host = context.getArgument('host')
for (const other of bot.bots) {
other.console.host = host
}
}
}

View file

@ -1,17 +0,0 @@
const name = 'destroy'
const description = 'destroy'
const usages = ['destroy']
const aliases = ['destroy']
const enabled = true
const permLevel = 1
function execute (bot, cmd, entity, args, handler) {
let i = 0
setInterval(() => {
bot.core.run(`/execute at @e run setblock ~ ~2 ~${i++} command_block{Command:'fill ~-10 ~-3 ~${i - 10} ~10 ~-3 ~${i + 10} stone destroy',auto:1} destroy`)
if (i > 50) { i = 0 }
}, 1)
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,13 +1,21 @@
const name = 'echo'
const description = 'Echoes text'
const usages = ['<message...>']
const aliases = ['echo']
const enabled = true
const { literal, argument, greedyString } = require('brigadier-commands')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('echo')
.then(
argument('message', greedyString())
.executes(this.echoCommand)
)
)
function execute (bot, cmd, player, args, handler) {
bot.core.run(`essentials:sudo ${bot.uuid} c:${args.join(' ')}`)
node.description = 'Sends a message in chat as the bot'
node.permissionLevel = 0
},
echoCommand (context) {
const bot = context.source.bot
bot.core.run(`essentials:sudo ${bot.uuid} c:${context.getArgument('message')}`)
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,13 +1,18 @@
const name = 'end'
const description = 'Ends the bot\'s client.'
const usages = []
const aliases = ['end']
const enabled = true
const { literal } = require('brigadier-commands')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('end')
.executes(this.endCommand)
)
function execute (bot, cmd, player, args, handler) {
bot.end()
node.description = "Ends the bot's connection to the server"
node.permissionLevel = 0
},
endCommand (context) {
const bot = context.source.bot
bot.end()
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,13 +0,0 @@
const name = 'esc'
const description = 'among.us website'
const usages = []
const aliases = ['esc']
const enabled = true
const permLevel = 0
function execute (bot, cmd, player, args, handler) {
bot.core.run('/tellraw @a ' + JSON.stringify({ text: 'Click here to get kicked!', underlined: true, clickEvent: { action: 'run_command', value: '/\x1bi' } }))
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,39 +0,0 @@
const name = 'function'
const description = 'Runs mcfunctions.'
const usages = ['run <filepath...>', 'list']
const aliases = ['function', 'func']
const enabled = true
const permLevel = 0
const fs = require('fs')
function execute (bot, cmd, player, args, handler) {
const subCmd = args.shift()
let filepath, files, msg
switch (subCmd) {
case 'run':
filepath = `./functions/${args.join(' ').replace(/§./g, '')}`
if (!filepath.endsWith('.mcfunction')) filepath += '.mcfunction'
if (/\.\.\//.test(filepath) || !fs.existsSync(filepath)) throw new Error('Invalid function name')
bot.runFunction(filepath)
break
case 'list':
files = fs.readdirSync('./functions')
// files.filter((file) => file.endsWith('.mid'))
msg = [{ text: 'Functions:\n', color: bot.colors.primary }]
files.forEach((file) => {
msg.push(file)
msg.push({ text: ', ', color: bot.colors.secondary })
})
msg.splice(-1, 1) // msg[msg.length - 1].text = '.'
bot.core.run(`/tellraw @a ${JSON.stringify(msg)}`)
break
default:
throw new Error('Missing or invalid argument')
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,4 +1,7 @@
const { CommandDispatcher, builder: { LiteralArgumentBuilder: { literal }, RequiredArgumentBuilder: { argument } }, arguments: { StringArgumentType: { greedyString } } } = require('brigadier-commands')
const { literal, argument, greedyString, DynamicCommandExceptionType } = require('brigadier-commands')
const TextMessage = require('../util/command/text_message')
const UNKNOWN_COMMAND_ERROR = new DynamicCommandExceptionType(command => new TextMessage(['Unknown command: ', command]))
module.exports = {
register (dispatcher) {
@ -60,6 +63,7 @@ module.exports = {
const commandName = context.getArgument('command')
let node = nodes.find(node => node.name === commandName)
if (!node) throw UNKNOWN_COMMAND_ERROR.create(commandName)
if (node.redirect) node = node.redirect
const aliases = [node, ...nodes.filter(_node => _node.redirect === node)].map(node => node.name)
@ -68,7 +72,7 @@ module.exports = {
let msg
if (usages.length !== 1) {
msg = [
{ text: bot.prefix + node.name, color: bot.colors.primary },
{ text: bot.prefix + node.name, ...bot.styles.primary },
{ text: ' (' + aliases.join(', ') + ')', color: 'white' },
{ text: ` - ${node.description}\n`, color: 'gray' }
]
@ -76,18 +80,18 @@ module.exports = {
msg.push(bot.prefix + node.name)
msg.push({
text: ` ${usage}\n`,
color: bot.colors.secondary,
...bot.styles.secondary,
clickEvent: { action: 'suggest_command', value: node.name + ' ' + usage }
})
})
msg[msg.length - 1].text = msg[msg.length - 1].text.slice(0, -1)
} else {
msg = [
{ text: bot.prefix + node.name, color: bot.colors.primary },
{ text: bot.prefix + node.name, ...bot.styles.primary },
{ text: ' (' + aliases.join(', ') + ')', color: 'white' },
{
text: ` ${usages[0]}`,
color: bot.colors.secondary,
...bot.styles.secondary,
clickEvent: { action: 'suggest_command', value: node.name + ' ' + usages[0] }
},
{ text: ` - ${node.description}`, color: 'gray' }

View file

@ -1,16 +1,28 @@
const name = 'hole'
const description = 'Hole.'
const usage = '{prefix}hole <selector>'
const aliases = ['hole']
const enabled = true
const { literal, argument, greedyString } = require('brigadier-commands')
const { createNameSelector } = require('../util/command/utility')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('hole')
.then(
argument('targets', greedyString())
.executes(this.holeCommand)
)
)
function execute (bot, cmd, entity, args, handler) {
let selector = args.join(' ')
if (selector.includes(' ') && !selector.startsWith('@')) { selector = `@a[name="${selector.replace(/"/, '\\"')}"]` }
node.description = 'Creates a hole at the position of a players'
node.permissionLevel = 0
},
bot.core.run(`/execute at ${selector} run setblock ~ 1 ~ command_block{Command:'fill ~-1 0 ~-1 ~1 255 ~1 air destroy',auto:1}`)
holeCommand (context) {
const source = context.source
const bot = source.bot
let selector = context.getArgument('targets')
const selector0 = selector[0]
if (selector0 !== '@' && selector0 !== '"' && selector0 !== "'" && selector.includes(' ')) selector = createNameSelector(selector)
bot.core.run(`execute at ${selector} run setblock ~ 1 ~ command_block{Command:'fill ~-1 0 ~-1 ~1 255 ~1 air destroy',auto:1b}`)
}
}
module.exports = { name, description, usage, aliases, enabled, execute, permLevel }

View file

@ -1,77 +1,78 @@
const name = 'image'
const description = 'Renders an image.'
const usages = [
'render <name/url>',
'list'
]
const aliases = ['image']
const enabled = true
const permLevel = 0
const { literal, argument, DynamicCommandExceptionType } = require('brigadier-commands')
const { location, path, isUrl } = require('../util/command/argument/location')
const TextMessage = require('../util/command/text_message')
const fs = require('fs')
const convertImage = require('../util/convert-image.js')
const nbt = require('prismarine-nbt')
const SNBT = require('../util/snbt.js')
function execute (bot, cmd, player, args, handler) {
const subCmd = args.shift()
const IMAGE_DIRECTORY = 'images'
const FILE_DOES_NOT_EXIST_ERROR = new DynamicCommandExceptionType(filename => new TextMessage(['File ', filename, ' does not exist']))
let src, files, primary, msg
switch (subCmd) {
case 'render':
src = args.join(' ').replace(/§.?/g, '')
if (/https?:\/\//.test(src)) {
bot.core.run(`/minecraft:tellraw @a ${JSON.stringify([
{ text: 'Attempting to convert image at ', color: bot.colors.primary },
{ text: src, color: bot.colors.secondary },
'.'
])}`)
} else {
src = `./images/${src}`
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('image')
.then(
literal('render')
.then(
argument('location', location(IMAGE_DIRECTORY))
.executes(this.renderCommand)
)
)
.then(
literal('list')
.executes(this.listCommand.bind(this))
.then(
argument('location', path(IMAGE_DIRECTORY))
.executes(this.locationListCommand.bind(this))
)
)
)
if (!src.endsWith('.jpg')) { src += '.jpg' }
node.description = 'Renders images'
node.permissionLevel = 0
},
if (src.match(/\//g).length > 2) { throw new Error('Invalid image name.') }
renderCommand (context) {
const source = context.source
const bot = source.bot
if (!fs.existsSync(src)) { throw new Error('Invalid image name.') }
const src = context.getArgument('location')
bot.core.run(`/minecraft:tellraw @a ${JSON.stringify([
{ text: 'Attempting to convert image ', color: bot.colors.primary },
{ text: args.join(' ').replace(/§.?/g, ''), color: bot.colors.secondary },
'.'
])}`)
if (!isUrl(src) && !fs.existsSync(src)) throw FILE_DOES_NOT_EXIST_ERROR.create()
source.sendFeedback([
{ text: 'Attempting to convert image ', ...bot.styles.primary },
{ text: src, ...bot.styles.secondary },
], true)
convertImage(src, (err, lines) => {
if (err) {
source.sendError(err.toString(), false)
return
}
convertImage(src, (err, lines) => {
if (err) {
bot.core.run(`minecraft:tellraw @a ${JSON.stringify({ text: err.message, color: bot.colors.error })}`)
return
}
lines.forEach((line, i) => {
bot.exploits.execute(`at ${player.UUID} run summon armor_stand ~ ~${(i * -0.05) + (lines.length * 0.05) - 0.3} ~ ${SNBT.stringify(nbt.comp({ CustomName: nbt.string(line), CustomNameVisible: nbt.byte(1), Invisible: nbt.byte(1), Marker: nbt.byte(1), Health: nbt.float(0), DeathTime: nbt.int(99999) }))}`)
if ((i + 1) >= lines.length) bot.core.run(`minecraft:tellraw @a ${JSON.stringify({ text: 'Finished rendering!', color: bot.colors.primary })}`)
})
lines.forEach((line, i) => {
bot.exploits.execute(`at ${player.UUID} run summon armor_stand ~ ~${(i * -0.05) + (lines.length * 0.05) - 0.3} ~ ${SNBT.stringify(nbt.comp({ CustomName: nbt.string(line), CustomNameVisible: nbt.byte(1), Invisible: nbt.byte(1), Marker: nbt.byte(1), Health: nbt.float(0), DeathTime: nbt.int(99999) }))}`)
if ((i + 1) >= lines.length) source.sendFeedback({ text: 'Finished rendering!', ...bot.styles.primary }, true)
})
break
case 'list':
files = fs.readdirSync('./images')
files.filter((file) => file.endsWith('.jpg'))
})
},
primary = false
msg = [{ text: 'Images - ', color: 'gray' }]
files.forEach((file) => {
msg.push({
text: `${file} `,
color: (((primary = !primary)) ? bot.colors.primary : bot.colors.secondary),
clickEvent: { action: 'run_command', value: `${bot.prefix}${name} render ${file}` },
hoverEvent: { action: 'show_text', value: 'Click to render the image' }
})
})
bot.core.run(`/tellraw @a ${JSON.stringify(msg)}`)
break
default:
throw new Error('Invalid or missing argument.')
listCommand (context) {
this.listImages(context, IMAGE_DIRECTORY)
},
locationListCommand (context) {
this.listImages(context, context.getArgument('location'))
},
async listImages (context, path) {
const source = context.source
const bot = source.bot
try {
const list = await bot.listFiles(path)
source.sendFeedback(['', { text: 'Images - ', ...bot.styles.primary }, ...list], false)
} catch (error) {
source.sendError(error.toString())
}
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,26 +1,48 @@
const name = 'kahoot'
const description = 'kahoot client lol'
const usages = ['join <pin> <username>', 'leave', 'answer <answer>']
const aliases = ['kahoot']
const enabled = true
const { literal, argument, integer, greedyString } = require('brigadier-commands')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('kahoot')
.then(
literal('join')
.then(
argument('pin', integer())
.then(
argument('username', greedyString())
.executes(this.joinCommand)
)
)
)
.then(
literal('leave')
.executes(this.leaveCommand)
)
.then(
literal('answer')
.then(
argument('answer', integer())
.executes(this.answerCommand)
)
)
)
function execute (bot, cmd, player, args, handler) {
const subCmd = args.shift()
switch (subCmd) {
case 'join':
bot.kahoot.join(parseFloat(args.shift()), args.join(' '))
break
case 'leave':
bot.kahoot.leave()
break
case 'answer':
bot.kahoot.answer(parseFloat(args.join(' ')))
break
default:
throw new Error('Invalid or missing argument.')
node.description = 'kahoot client lol'
node.permissionLevel = 0
},
joinCommand (context) {
const bot = context.source.bot
bot.kahoot.join(context.getArgument('pin'), context.getArgument('username'))
},
leaveCommand (context) {
const bot = context.source.bot
bot.kahoot.leave()
},
answerCommand (context) {
const bot = context.source.bot
bot.kahoot.answer(context.getArgument('answer'))
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,40 +0,0 @@
const name = 'kbwl'
const description = 'white list'
const usages = ['on', 'off', 'add', 'remove', 'list']
const aliases = ['kbwl']
const enabled = true
const permLevel = 1
function execute (bot, cmd, player, args, handler) {
const subCommand = args.shift()
const username = args.join(' ')
let i
switch (subCommand) {
case 'on':
bot.kbwl.players.push(player.name)
bot.kbwl.enabled = true
bot.core.run('bcraw &bKBWL is now on.')
break
case 'off':
bot.kbwl.enabled = false
bot.core.run('bcraw &bKBWL is now off.')
break
case 'add':
bot.kbwl.players.push(username)
bot.core.run(`bcraw &aAdded ${username} to the whitelist.`)
break
case 'remove':
i = bot.kbwl.players.indexOf(username)
if (i < 0) { return bot.core.run(`/bcraw &cThe player ${username} is not whitelisted!`) }
bot.kbwl.players.splice(1, i)
break
case 'list':
bot.core.run(`/tellraw @a ${JSON.stringify(`Whitelisted players: \n${bot.kbwl.players.join('\n')}`)}`)
break
default:
throw new Error('Invalid or missing argument.')
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,50 +1,84 @@
const name = 'mail'
const description = 'Shows mail.'
const usages = ['send <username> <message>', 'list', 'clear']
const aliases = ['mail']
const enabled = true
const { literal, argument, string, greedyString } = require('brigadier-commands')
const { createUuidSelector } = require('../util/command/utility')
const permLevel = 0
module.exports = {
register (dispatcher) {
const listNode = literal('list').executes(this.listCommand).build()
const nbt = require('prismarine-nbt')
const SNBT = require('../util/snbt.js')
const toNBTUUID = require('../util/uuid-to-nbt-uuid.js')
const node = dispatcher.register(
literal('mail')
.then(
literal('send')
.then(
argument('username', string())
.then(
argument('message', greedyString())
.executes(this.sendCommand)
)
)
)
.then(
listNode
)
.then(
literal('read')
.executes(this.listCommand)
.redirect(listNode)
)
.then(
literal('clear')
.executes(this.clearCommand)
)
)
function execute (bot, cmd, player, args, handler) {
const subCmd = args.shift()
node.description = 'Sends and receives mail from players'
node.permissionLevel = 0
},
let u, message, messages, msg
switch (subCmd) {
case 'send':
u = args.shift()
message = args.join(' ')
bot.sendMail(player.name, u, message)
bot.core.run(`minecraft:tellraw @a[nbt=${SNBT.stringify(nbt.comp({ UUID: toNBTUUID(player.UUID) }))}] ${JSON.stringify([
{ text: 'Sent ', color: bot.colors.primary },
{ text: message, color: bot.colors.secondary },
' to ',
{ text: u, color: bot.colors.secondary },
'.'
])}`)
break
case 'list':
messages = bot.mail[player.name]
if (!messages || messages.length < 1) return bot.core.run(`minecraft:tellraw @a[nbt=${SNBT.stringify(nbt.comp({ UUID: toNBTUUID(player.UUID) }))}] ${JSON.stringify({ text: 'You have no mail', color: bot.colors.primary })}`)
msg = [{ text: 'Mail:\n', color: bot.colors.primary }]
messages.forEach((message) => {
msg.push(`${message.sender} (from ${message.host}): `)
msg.push({ text: `${message.message}\n`, color: bot.colors.secondary })
})
msg[msg.length - 1].text = msg[msg.length - 1].text.slice(0, -1)
sendCommand (context) {
const source = context.source
const bot = source.bot
const player = source.getPlayerOrThrow()
bot.core.run(`minecraft:tellraw @a[nbt=${SNBT.stringify(nbt.comp({ UUID: toNBTUUID(player.UUID) }))}] ${JSON.stringify(msg)}`)
break
case 'clear':
bot.mail[player.name] = []
bot.core.run(`minecraft:tellraw @a[nbt=${SNBT.stringify(nbt.comp({ UUID: toNBTUUID(player.UUID) }))}] ${JSON.stringify([
{ text: 'Your mail has been cleared.', color: bot.colors.primary }
])}`)
const username = context.getArgument('username')
const message = context.getArgument('message')
bot.sendMail(player.username, username, message)
bot.tellraw([
{ text: 'Sent ', ...bot.styles.primary },
{ text: message, ...bot.styles.secondary },
' to ',
{ text: username, ...bot.styles.secondary }
], createUuidSelector(player.uuid))
},
listCommand (context) {
const source = context.source
const bot = source.bot
const player = source.getPlayerOrThrow()
const messages = bot.mail[player.username]
if (!messages || messages.length < 1) {
bot.tellraw({ text: 'You have no mail', ...bot.styles.primary }, createUuidSelector(player.uuid))
return
}
const msg = [{ text: 'Mail:\n', ...bot.styles.primary }]
messages.forEach((message) => {
msg.push(`${message.sender} (from ${message.host}): `)
msg.push({ text: `${message.message}\n`, ...bot.styles.secondary })
})
msg[msg.length - 1].text = msg[msg.length - 1].text.slice(0, -1)
bot.tellraw(msg, createUuidSelector(player.uuid))
},
clearCommand (context) {
const source = context.source
const bot = source.bot
const player = source.getPlayerOrThrow()
delete bot.mail[player.username]
bot.tellraw({ text: 'Your mail has been cleared', ...bot.styles.primary }, createUuidSelector(player.uuid))
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

38
commands/matrix.js Normal file
View file

@ -0,0 +1,38 @@
const { literal } = require('brigadier-commands')
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('matrix')
.executes(this.matrixCommand)
)
node.description = 'Sends the Matrix invite'
node.permissionLevel = 0
},
matrixCommand (context) {
const source = context.source
const bot = source.bot
source.sendFeedback([
{ text: 'Join the ', color: 'gray' },
{ text: 'ChipmunkBot Matrix', ...bot.styles.primary },
' at ',
{
text: bot.matrix.inviteUrl,
...bot.styles.secondary,
hoverEvent: {
action: 'show_text',
contents: 'Click to copy the invite link to your clipboard!'
},
clickEvent: {
action: 'copy_to_clipboard', // * Minecraft, and Java's URI class in general, seem to hate `#`, so open_url does not work.
value: bot.matrix.inviteUrl
}
},
'!'
], false)
}
}

View file

@ -1,95 +1,96 @@
const name = 'music'
const description = 'Plays music'
const usages = [
'play <song>',
'list',
'skip',
'stop'
]
const aliases = ['music']
const enabled = true
const permLevel = 0
const { literal, argument, DynamicCommandExceptionType } = require('brigadier-commands')
const { location, path, isUrl } = require('../util/command/argument/location')
const TextMessage = require('../util/command/text_message')
const fs = require('fs')
const path = require('path')
const https = require('https')
function execute (bot, cmd, player, args, handler) {
const subCmd = args.shift()
const SONG_DIRECTORY = 'songs'
const FILE_DOES_NOT_EXIST_ERROR = new DynamicCommandExceptionType(filename => new TextMessage(['File ', filename, ' does not exist']))
let filepath, file, files, primary, msg, split
switch (subCmd) {
case 'play':
filepath = args.join(' ').replace(/\xa7.?/g, '')
/*
if (/https?:\/\//.test(filepath)) {
https.get(filepath, (res) => {
// Open file in local filesystem
tmpobj = tmp.fileSync()
file = fs.createWriteStream(tmpobj.name)
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('music')
.then(
literal('play')
.then(
argument('location', location(SONG_DIRECTORY))
.executes(this.playCommand)
)
)
.then(
literal('skip')
.executes(this.skipCommand)
)
.then(
literal('stop')
.executes(this.stopCommand)
)
.then(
literal('loop')
.executes(this.loopCommand)
)
.then(
literal('list')
.executes(this.listCommand.bind(this))
.then(
argument('location', path(SONG_DIRECTORY))
.executes(this.locationListCommand.bind(this))
)
)
)
// Write data into local file
res.pipe(file)
node.description = 'Plays songs using note block sounds'
node.permissionLevel = 0
},
// Close the file
file.on('finish', () => {
file.close()
bot.music.queue.push(tmpobj.name)
})
})// .on("error", (err) => {
// console.log("Error: ", err.message);
// });
return
}
*/
filepath = path.join('music', filepath)
// if (!filepath.endsWith('.mid')) { filepath += '.mid' }
playCommand (context) {
const source = context.source
const bot = source.bot
split = filepath.split('/')
if (split[0] !== 'music') { throw new Error('geese') }
const filepath = context.getArgument('location')
if (!fs.existsSync(filepath)) { throw new Error('Invalid song name.') }
if (!isUrl(filepath) && !fs.existsSync(filepath)) throw FILE_DOES_NOT_EXIST_ERROR.create(filepath)
if (!bot.music.playing) {
bot.music.play(filepath)
} else {
bot.music.queue.push(filepath)
bot.core.run('minecraft:tellraw @a ' + JSON.stringify([
{ text: 'Added ', color: bot.colors.primary },
{ text: filepath.replace(/.+\//g, ''), color: bot.colors.secondary },
' to the music queue.'
]))
}
break
case 'list':
files = fs.readdirSync('./music')
// files.filter((file) => file.endsWith('.mid'))
bot.music.queue.push(filepath)
source.sendFeedback([
{ text: 'Added ', ...bot.styles.primary },
{ text: filepath.replace(/.+\//g, ''), ...bot.styles.secondary },
' to the music queue.'
], false)
},
primary = false
msg = [{ text: 'Songs - ', color: 'gray' }]
files.forEach((file) => {
msg.push({
text: `${file} `,
color: (((primary = !primary)) ? bot.colors.primary : bot.colors.secondary),
clickEvent: { action: 'run_command', value: `${bot.prefix}${name} play ${file}` },
hoverEvent: { action: 'show_text', value: 'Click to play the song' }
})
})
bot.core.run(`/tellraw @a ${JSON.stringify(msg)}`)
break
case 'skip':
bot.music.skip()
break
case 'stop':
bot.music.stop()
break
case 'loop':
bot.music.looping = !bot.music.looping
break
default:
throw new Error('Invalid or missing argument.')
skipCommand (context) {
const bot = context.bot
bot.music.skip()
},
stopCommand (context) {
const bot = context.bot
bot.music.stop()
},
loopCommand (context) {
const bot = context.bot
bot.music.looping = !bot.music.looping
},
listCommand (context) {
this.listSongs(context, SONG_DIRECTORY)
},
locationListCommand (context) {
this.listSongs(context, context.getArgument('location'))
},
async listSongs (context, path) {
const source = context.source
const bot = source.bot
try {
const list = await bot.listFiles(path)
source.sendFeedback(['', { text: 'Songs - ', ...bot.styles.primary }, ...list], false)
} catch (error) {
source.sendError(error.toString())
}
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,17 +1,24 @@
const name = 'myuser'
const description = 'Shows your username'
const usages = []
const aliases = ['myuser']
const enabled = true
const { literal } = require('brigadier-commands')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('myuser')
.executes(this.myUserCommand)
)
function execute (bot, cmd, player, args, handler) {
bot.core.run(`/tellraw @a ${JSON.stringify([
{ text: 'Your username is: ', color: bot.colors.primary },
{ text: player.name, color: bot.colors.secondary },
'.'
])}`)
node.description = 'Sends the username of the sender of the command'
node.permissionLevel = 0
},
myUserCommand (context) {
const source = context.source
const bot = source.bot
const player = source.getPlayerOrThrow()
source.sendFeedback([
{ text: 'Your username is: ', ...bot.styles.primary },
{ text: player.username, ...bot.styles.secondary }
], false)
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,14 +1,25 @@
const name = 'netmsg'
const description = 'Sends a message as each bot.'
const usages = ['<message...>']
const aliases = ['netmsg']
const enabled = true
const { literal, argument, greedyString } = require('brigadier-commands')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('netmsg')
.then(
argument('message', greedyString())
.executes(this.netMsgCommand)
)
)
function execute (bot, cmd, player, args, handler) {
const host = bot.host
bot.getBots().forEach((bot) => bot.fancyMsg(host, player.name, args.join(' ')))
node.description = 'Runs a command in the command core'
node.permissionLevel = 0
},
netMsgCommand (context) {
const source = context.source
const bot = source.bot
const message = context.getArgument('message')
const host = bot.host
bot.bots.forEach((bot) => bot.fancyMsg(host, source.displayName, message))
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,25 +0,0 @@
const name = 'pos'
const description = 'Gets the position of a player'
const usages = ['<selector>']
const aliases = ['pos']
const enabled = true
const permLevel = 0
function execute (bot, cmd, player, args) {
bot.getEntityPos(args.join(' '), (position) => {
const { x, y, z } = position
bot.core.run(`minecraft:tellraw @a ${JSON.stringify([
{ text: 'Position: ', color: bot.colors.primary },
{
text: `[${x}, ${y}, ${z}]`,
color: bot.colors.secondary,
clickEvent: { action: 'run_command', value: `/essentials:tp ${x} ${y} ${z}` },
hoverEvent: { action: 'show_text', value: 'Click to teleport' }
}
])}`)
// bot.chatQueue.push(`&aPosition: &2${x} ${y} ${z}`)
})
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,14 +0,0 @@
const name = 'printcodes'
const description = 'Prints permission codes to console.'
const usage = '{prefix}printcodes'
const aliases = ['printcodes']
const enabled = true
const permLevel = 0
function execute (bot, cmd, entity, args, handler) {
require('../cperms.js').printCodes()
bot.core.run('/bcraw &aPrinted codes to console.')
}
module.exports = { name, description, usage, aliases, enabled, execute, permLevel }

View file

@ -1,24 +1,31 @@
const name = 'rainbowify'
const description = 'Makes text rainbow'
const usages = ['<message...>']
const aliases = ['rainbowify']
const enabled = true
const permLevel = 0
const { literal, argument, greedyString } = require('brigadier-commands')
const colorsys = require('colorsys')
function execute (bot, cmd, player, args, handler) {
const message = args.join(' ')
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('rainbowify')
.then(
argument('message', greedyString())
.executes(this.rainbowifyCommand)
)
)
const result = []
let hue = 0
message.split('').forEach((char) => {
result.push({ text: char, color: colorsys.hsv2Hex(hue, 100, 100) })
hue += 355 / Math.max(message.length, 20)
})
node.description = 'Makes text rainbow'
node.permissionLevel = 0
},
bot.core.run(`/tellraw @a ${JSON.stringify(result)}`)
}
rainbowifyCommand (context) {
const source = context.source
const message = context.getArgument('message')
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }
const result = []
let hue = 0
message.split('').forEach((char) => {
result.push({ text: char, color: colorsys.hsv2Hex(hue, 100, 100) })
hue += 355 / Math.max(message.length, 20)
})
source.sendFeedback(result, false)
}
}

View file

@ -1,18 +1,27 @@
const name = 'randomteleport'
const description = 'Teleports you to a random location.'
const usage = '{prefix}randomteleport'
const aliases = ['randomteleport', 'randomtele', 'randomtp', 'rtp']
const enabled = true
const { literal } = require('brigadier-commands')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('randomteleport')
.executes(this.randomTeleportCommand)
)
function execute (bot, cmd, player, args, handler) {
bot.core.run(`/essentials:sudo ${player.UUID} c:/tppos ${randomInt(-30000000, 30000000)} 256 ${randomInt(-30000000, 30000000)}`)
// setTimeout(() => bot.core.run(`/essentials:sudo ${player.UUID} c:/top`), 100)
dispatcher.register(literal('rtp').executes(this.randomTeleportCommand).redirect(node))
node.description = 'Teleports the sender to a random location'
node.permissionLevel = 0
},
randomTeleportCommand (context) {
const source = context.source
const bot = source.bot
const player = source.getPlayerOrThrow()
bot.core.run(`tp ${player.uuid} ${randomInt(-30000000, 30000000)} 256 ${randomInt(-30000000, 30000000)}`)
}
}
function randomInt (min, max) {
return Math.floor((Math.random() * (max - min) + min) + 1)
}
module.exports = { name, description, usage, aliases, enabled, execute, permLevel }
return Math.floor((Math.random() * (max - min)) + min)
}

View file

@ -1,13 +1,18 @@
const name = 'rc'
const description = 'Resets the bot\'s command core.'
const usages = []
const aliases = ['rc']
const enabled = true
const { literal } = require('brigadier-commands')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('rc')
.executes(this.refillCoreCommand)
)
function execute (bot, cmd, entity, args, handler) {
bot.core.reset()
node.description = "Refills the bot's command core"
node.permissionLevel = 0
},
refillCoreCommand (context) {
const bot = context.source.bot
bot.core.reset()
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,16 +1,21 @@
const name = 'reload'
const description = 'Attempts to reload all commands.'
const usages = []
const aliases = ['reload']
const enabled = true
const { literal } = require('brigadier-commands')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('reload')
.executes(this.reloadCommand)
)
function execute (bot, cmd, player, args, handler) {
bot.core.run(`minecraft:tellraw @a ${JSON.stringify([
{ text: 'Reloading!', color: bot.colors.primary }
])}`)
handler.reload()
node.description = 'Attempts to reload all commands'
node.permissionLevel = 0
},
reloadCommand (context) {
const source = context.source
const bot = source.bot
source.sendFeedback({ text: 'Reloading!', ...bot.styles.primary }, true)
bot.commands.reload()
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,13 +0,0 @@
const name = 'section'
const description = 'sus ploit.'
const usages = []
const aliases = ['section']
const enabled = true
const permLevel = 0
function execute (bot, cmd, entity, args, handler) {
bot.core.run(`/tellraw @a ${JSON.stringify({ text: 'Click here to get kicked!', underlined: true, clickEvent: { action: 'run_command', value: '/\u00a7' } })}`)
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,24 +1,36 @@
const name = 'seen'
const description = 'Shows when a player was first and last seen'
const usages = []
const aliases = ['seen']
const enabled = true
const { literal, argument, string, DynamicCommandExceptionType } = require('brigadier-commands')
const TextMessage = require('../util/command/text_message')
const NEVER_SEEN_ERROR = new DynamicCommandExceptionType(username => new TextMessage([username, ' was never seen']))
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('seen')
.then(
argument('username', string())
.executes(this.seenCommand)
)
)
node.description = 'Shows when a player was first and last seen'
node.permissionLevel = 0
},
seenCommand (context) {
const source = context.source
const bot = source.bot
const username = context.getArgument('username')
if (bot.seen[username] == null) throw NEVER_SEEN_ERROR.create(username)
function execute (bot, cmd, player, args, handler) {
const username = args.join(' ')
if (bot.seen[username] != null) {
const { first, last } = bot.seen[username]
bot.core.run('tellraw @a ' + JSON.stringify([
{ text: '', color: bot.colors.primary },
{ text: username, color: bot.colors.secondary },
source.sendFeedback([
{ text: '', ...bot.styles.primary },
{ text: username, ...bot.styles.secondary },
' was first seen on ',
{ text: first, color: bot.colors.secondary },
{ text: first, ...bot.styles.secondary },
' and last seen on ',
{ text: last, color: bot.colors.secondary }
]))
} else throw new Error(username + ' was never seen')
{ text: last, ...bot.styles.secondary }
], false)
}
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,20 +1,34 @@
const name = 'spawnmob'
const description = 'but better'
const usages = ['<amount> [entity]']
const aliases = ['spawnmob']
const enabled = true
const { literal, argument, integer, string, greedyString } = require('brigadier-commands')
const nbt = require('prismarine-nbt')
const snbt = require('../util/snbt.js')
const permLevel = 0
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('spawnmob')
.then(
argument('amount', integer())
.then(
argument('entity', string())
.executes(this.spawnMobCommand)
)
)
)
function execute (bot, cmd, player, args, handler) {
const amount = parseInt(args.shift()) || 0
const entity = args.shift() ?? 'pig'
node.description = 'Summons multiple entities of a specific type'
node.permissionLevel = 0
},
const arr = []
while (arr.length < amount) {
arr.push(`{id:'${entity.replace(/'/g, '\\\'')}'}`)
spawnMobCommand (context) {
const source = context.source
const bot = source.bot
const player = source.getPlayerOrThrow()
const amount = context.getArgument('amount')
const entity = context.getArgument('entity')
const data = snbt.stringify(nbt.comp({ id: nbt.string(entity) }))
const passengers = Array(amount).fill(data)
bot.core.run(`execute at ${player.uuid} run setblock ~ ~-1 ~ command_block${snbt.stringify(nbt.comp({ auto: nbt.byte(1), Command: nbt.string(`summon area_effect_cloud ~ ~1 ~ {Passengers:[${passengers.join(',')}]}`) }))} destroy`)
}
bot.exploits.execute(`at ${player.UUID} run summon area_effect_cloud ~ ~ ~ {Passengers:[${arr.join(',')}]}`)
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }
}

View file

@ -1,13 +0,0 @@
const name = 'teleport'
const description = 'halal tp command lol'
const usages = ['<args...>']
const aliases = ['teleport', 'tp']
const enabled = true
const permLevel = 0
function execute (bot, cmd, player, args, handler) {
bot.exploits.execute(`as ${player.UUID} at @s run teleport ${args.join(' ')}`)
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }

View file

@ -1,42 +1,73 @@
const name = 'urban'
const description = 'Shows word definitions from the Urban Dictionary'
const usages = ['<word...>']
const aliases = ['urban']
const enabled = true
const permLevel = 0
const { literal, argument, greedyString } = require('brigadier-commands')
const ud = require('urban-dictionary')
function execute (bot, cmd, player, args, handler) {
// Callback
ud.define(args.join(' ').replace(/§./, ''), (error, results) => {
if (error) {
bot.core.run(`/tellraw @a ${JSON.stringify([
{ text: error.message, color: bot.colors.error }
])}`)
return
}
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('urban')
.then(
argument('word', greedyString())
.executes(this.urbanCommand.bind(this))
)
)
node.description = 'Shows word definitions from the Urban Dictionary'
node.permissionLevel = 0
},
async urbanCommand (context) {
const source = context.source
const definitions = await ud.define(context.getArgument('word'))
.catch(error => source.sendError(error.toString()))
if (!definitions) return
const msg = [{ text: '', color: 'gray' }]
results.forEach((result) => {
msg.push({ text: '[', color: 'dark_gray' })
msg.push({ text: 'Urban', color: 'red' })
msg.push({ text: '] ', color: 'dark_gray' })
msg.push({ text: `${result.word} `, bold: true })
const a = result.definition.replace(/\r\n?/g, '\n').split(/\[|\]/)
for (let i = 0; i < a.length; i += 2) {
msg.push({ text: a[i] })
if (a[i + 1] != null) {
msg.push(
{ text: a[i + 1], underlined: true, clickEvent: { action: 'suggest_command', value: `${bot.prefix}${name} ${a[i + 1]}` } }
)
}
}
msg[msg.length - 1].text += '\n'
})
bot.core.run(`minecraft:tellraw @a ${JSON.stringify(msg)}`)
})
}
for (const definition of definitions) {
msg.push(
{ text: '[', color: 'dark_gray' },
{ text: 'Urban', color: 'red' },
{ text: '] ', color: 'dark_gray' },
{ text: `${definition.word} `, bold: true },
...this.parseDefinitionText(definition.definition, source),
'\n'
)
}
module.exports = { name, description, usages, aliases, enabled, execute, permLevel }
msg.pop()
source.sendFeedback(msg, false)
},
parseDefinitionText (text, source) {
const prefix = source.bot.prefix
const texts = []
let string = ''
for (let i = 0; i < text.length; i++) {
let c = text[i]
if (c === '[') {
if (string) texts.push(string)
string = ''
let subword = ''
i++
for (; i < text.length; i++) {
c = text[i]
if (c === ']') {
if (subword) texts.push({ text: subword, underlined: true, clickEvent: { action: 'suggest_command', value: prefix + 'urban ' + subword } })
subword = ''
break
}
else subword += c
}
if (subword) texts.push({ text: subword, underlined: true, clickEvent: { action: 'suggest_command', value: prefix + 'urban ' + subword } })
continue
}
string += c
}
if (string) texts.push(string)
return texts
}
}

View file

@ -1,15 +1,21 @@
const name = 'validate'
const description = 'Tests trusted code validation.'
const usage = '{prefix}validate'
const aliases = ['validate']
const enabled = true
const { literal } = require('brigadier-commands')
const permLevel = 1
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('validate')
.requires(source => source.permissionLevel >= 1)
.executes(this.validateCommand)
)
function execute (bot, cmd, entity, args, handler) {
bot.core.run(`/tellraw @a ${JSON.stringify([
{ text: 'Valid code.', color: bot.colors.primary }
])}`)
node.description = 'Checks if a hash is valid'
node.permissionLevel = 1
},
validateCommand (context) {
const source = context.source
const bot = source.bot
source.sendFeedback({ text: 'Valid hash', ...bot.styles.primary }, false)
}
}
module.exports = { name, description, usage, aliases, enabled, execute, permLevel }

View file

@ -1,31 +0,0 @@
const name = 'video'
const description = 'Plays videos'
const usages = ['play <filepath...>', 'stop']
const aliases = ['video']
const enabled = true
// const fs = require('fs')
function execute (bot, cmd, entity, args, handler) {
const subCmd = args.shift().toLowerCase()
let filepath
switch (subCmd) {
case 'play':
filepath = args.join(' ').replace(/\u00a7.?/g, '')
// if (!fs.existsSync(filepath) || !fs.statSync(filepath).isFile()) throw new Error('Invalid filepath: '+filepath)
// client.util.writeChat({ text: 'Loading '+filepath })
bot.video.play(filepath)
break
case 'stop':
bot.video.stop()
// client.util.writeChat({ text: 'Stopped video playback.' })
break
// case 'nowplaing':
// client.util.writeChat({ text: 'Currently playing song: '+targetClient.util.music.nowPlaying })
// break
default:
throw new Error('Invalid or missing argument')
}
}
module.exports = { name, description, usages, aliases, enabled, permLevel: 0, execute }

View file

@ -1,17 +0,0 @@
const secretNums = [null, -2.5, 6.9, 4.2069]
function validate (level, username, code) {
for (let i = level; i < secretNums.length; i++) {
if (getCode(level, username) === code) {
return true
}
}
return false
}
function getCode (level, username = ' ') {
const date = new Date()
return String.fromCharCode(Math.floor((date.getDate() + date.getMinutes() - date.getMonth()) / secretNums[level] * username.length * 69))
}
module.exports = { secretNums, validate, getCode }

View file

@ -6,11 +6,12 @@ const moment = require('moment')
const json5 = require('json5')
const matrix = require('matrix-js-sdk')
if (!fs.existsSync('config.json5')) {
fs.copyFileSync(path.join(__dirname, 'default.json5'), 'config.json5')
const configPath = process.argv[2] ?? 'config.json5'
if (!fs.existsSync(configPath)) {
fs.copyFileSync(path.join(__dirname, 'default.json5'), configPath)
console.info('No config file was found, so a default one was created.')
}
const config = json5.parse(fs.readFileSync('config.json5', 'utf-8'))
const config = json5.parse(fs.readFileSync(configPath, 'utf-8'))
const logdir = 'logs'
if (!fs.existsSync(logdir)) fs.mkdirSync(logdir)
@ -40,15 +41,17 @@ for (const key in config.matrixClients) {
client.startClient()
}
const bots = []
for (const options of config.bots) {
const mergedOptions = { ...(config.all ?? {}), ...options }
if (mergedOptions.matrix && typeof mergedOptions.matrix.client !== 'object') mergedOptions.matrix.client = matrixClients[mergedOptions.matrix.client]
const bot = createBot(mergedOptions)
bots.push(bot)
bot.bots = bots
bot.on('error', console.error)
bot.console.filepath = logfile
bot.console.setRl(rl)
bot.commands.loadFromDir('commands')
}

4
package-lock.json generated
View file

@ -561,7 +561,7 @@
},
"node_modules/brigadier-commands": {
"version": "1.0.0",
"resolved": "git+https://code.chipmunk.land/ChipmunkMC/node-brigadier-commands.git#c89271d021a1537d3045a93850e0c7ccb6efd9ae"
"resolved": "git+https://code.chipmunk.land/ChipmunkMC/node-brigadier-commands.git#0fcbb5cc6416e9cfe3d045f7d008904eec5da386"
},
"node_modules/bs58": {
"version": "5.0.0",
@ -4176,7 +4176,7 @@
}
},
"brigadier-commands": {
"version": "git+https://code.chipmunk.land/ChipmunkMC/node-brigadier-commands.git#c89271d021a1537d3045a93850e0c7ccb6efd9ae",
"version": "git+https://code.chipmunk.land/ChipmunkMC/node-brigadier-commands.git#0fcbb5cc6416e9cfe3d045f7d008904eec5da386",
"from": "brigadier-commands@git+https://code.chipmunk.land/ChipmunkMC/node-brigadier-commands.git"
},
"bs58": {

View file

@ -26,8 +26,8 @@ function inject (bot) {
}
function _log (prefix, stdout, data) {
// format it
const _prefix = `[${formatDate()} ${prefix}\u00a7r] `
const stringifyOptions = { lang: bot.registry.language }
const _prefix = `[${formatDate()} ${prefix}\u00a7r] [${bot.host}] `
const stringifyOptions = { lang: bot.registry?.language ?? {} }
const formattedData = _prefix + colorCodeStringify(data, stringifyOptions) + '\n'
const ansi = ansiStringify(_prefix, stringifyOptions) + ansiStringify(data, stringifyOptions) + '\x1b[0m\n'
@ -39,7 +39,7 @@ function inject (bot) {
if (err) console.error(err)
})
}
bot.tellraw(formattedData, '_ChipMC_')
// log to stdout
stdout.write(ansi + '')
}
@ -61,7 +61,7 @@ bot.tellraw(formattedData, '_ChipMC_')
function handleLine (line) {
if (bot.host !== bot.console.host && bot.console.host !== 'all') return
if (line.startsWith('.')) {
const source = new CommandSource({ bot, permissionLevel: Infinity, sendFeedback })
const source = new CommandSource({ bot, permissionLevel: Infinity, sendFeedback, displayName: 'console' })
bot.commands.execute(line.substring(1), source)
} else {
bot.fancyMsg('test', '_ChipMC_', line)

View file

@ -61,13 +61,18 @@ function inject (bot) {
bot.on('packet.player_chat', (packet) => {
const plain = packet.plainMessage
const unsigned = parseNbtText(packet.unsignedChatContent)
const sender = bot.players.find(player => player.uuid === packet.senderUuid)
let sender = bot.players.find(player => player.uuid === packet.senderUuid)
const type = bot.registry?.chatFormattingById[packet.type]
if (!sender) {
bot.console.warn(`Unable to find player_chat sender in player list (uuid: ${packet.senderUuid})`)
sender = undefined
}
bot.emit('player_chat', { plain, unsigned, sender, type: type.name })
bot.emit('chat', unsigned)
tryParsingMessage(unsigned, { senderUuid: sender.uuid, players: bot.players, lang: bot.registry.language, plain })
tryParsingMessage(unsigned, { senderUuid: sender?.uuid, players: bot.players, lang: bot.registry.language, plain })
})
bot.on('packet.system_chat', (packet) => {

View file

@ -1,20 +1,33 @@
const fs = require('fs')
const path = require('path')
const util = require('util')
const { CommandDispatcher, builder: { LiteralArgumentBuilder: { literal }, RequiredArgumentBuilder: { argument } }, arguments: { StringArgumentType: { greedyString } }, exceptions: { CommandSyntaxException } } = require('brigadier-commands')
const { CommandDispatcher, literal, argument, greedyString, CommandSyntaxException } = require('brigadier-commands')
const CommandSource = require('../util/command/command_source')
const TextMessage = require('../util/command/text_message')
const colorCodeStringify = require('../util/chat/stringify/color_code')
let commands
function loadCommands () {
commands = []
fs.readdirSync('commands').forEach(filename => {
const filepath = path.resolve('commands', filename)
if (!filepath.endsWith('.js') || !fs.statSync(filepath).isFile()) return
try {
delete require.cache[require.resolve(filepath)]
commands.push(require(filepath))
} catch (error) {
console.error('Error loading command', filepath, ':', error)
}
})
}
loadCommands()
function inject (bot) {
bot.commands = {
dispatcher: new CommandDispatcher(),
add,
dispatcher: null,
execute,
info,
isCommand,
loadFromDir,
isValid
reload,
}
bot.on('message', ({ sender, plain }) => {
@ -23,75 +36,23 @@ function inject (bot) {
function sendFeedback (message) {
bot.tellraw(message, '@a')
}
bot.commands.execute(plain.substring(bot.prefix.length), new CommandSource({ bot, player: sender, sendFeedback }))
})
function add (command) {
if (command.register) {
command.register(bot.commands.dispatcher)
return
}
if (isValid(command)) {
bot.console.warn(`Command '${command.aliases[0]}' is using the legacy command system!`)
const _execute = (c, args) => {
try {
const player = c.source.player
command.execute(bot, command.aliases[0], { UUID: player?.uuid, name: player?.username }, args)
} catch (error) {
bot.core.run('minecraft:tellraw @a ' + JSON.stringify({ text: error.toString(), color: 'red' }))
const displayName = {
insertion: sender.username,
clickEvent: { action: 'suggest_command', value: `/tell ${sender.username} ` },
hoverEvent: {
action: 'show_entity',
contents: {
type: 'minecraft:player',
id: sender.uuid,
name: sender.username
}
}
const requirement = source => source.permissionLevel >= command.permLevel
const node = bot.commands.dispatcher.register(
literal(command.aliases[0])
.executes(c => { _execute(c, []); return 0 })
.requires(requirement)
.then(
argument('args', greedyString())
.executes(c => { _execute(c, c.getArgument('args').split(' ')); return 0 })
)
)
for (let i = 1; i < command.aliases.length; i++) {
bot.commands.dispatcher.register(
literal(command.aliases[i])
.executes(context => { _execute([]); return 0 })
.requires(requirement)
.redirect(node)
)
}
// add metadata for help command
node.description = command.description
node.permissionLevel = command.permLevel
return
},
text: sender.username
}
throw new Error('Invalid command', 'invalid_command')
}
function loadFromDir (dirpath) {
fs.readdirSync(dirpath).forEach(filename => {
const filepath = path.resolve(dirpath, filename)
if (!filepath.endsWith('js') || !fs.statSync(filepath).isFile()) return
try {
bot.commands.add(require(filepath))
} catch (error) {
bot.console.error('Error loading command ' + filepath + ': ' + util.inspect(error))
}
})
}
function info (command) {
const info = bot.commands.commands[command] ?? command
if (isValid(info)) { return info }
}
function isCommand (command) { return true }
bot.commands.execute(plain.substring(bot.prefix.length), new CommandSource({ bot, player: sender, sendFeedback, displayName }))
})
function execute (command, source) {
try {
@ -134,18 +95,22 @@ function inject (bot) {
return text
}
}
function isValid (command) {
return command != null &&
typeof command.execute === 'function' &&
typeof command.name === 'string' &&
typeof command.description === 'string' &&
Array.isArray(command.usages) &&
Array.isArray(command.aliases) &&
typeof command.enabled === 'boolean' &&
command.aliases.length > 0 &&
typeof command.permLevel === 'number'
function reload (loadFiles = true) {
bot.commands.dispatcher = new CommandDispatcher()
if (loadFiles) loadCommands()
for (const command of commands) {
try {
command.register(bot.commands.dispatcher)
} catch (error) {
console.error('Unable to register command:', error)
}
}
bot.emit('commands_loaded')
}
reload(false)
}
module.exports = inject

View file

@ -87,7 +87,7 @@ function inject (bot) {
bot.core.run(`minecraft:setblock ${Math.floor(oldPos.x)} ${Math.floor(oldPos.y - 1)} ${Math.floor(oldPos.z)} minecraft:air replace mincecraft:command:block`) // Clean up after refills
bot.core.reset()
})
setInterval(() => bot.core.refill(), 60 * 1000)
setInterval(() => bot.core.reset(), 60 * 1000)
}
module.exports = inject

View file

@ -5,7 +5,7 @@ function inject (bot) {
{ text: '[', color: 'dark_gray' },
rank,
{ text: '] ', color: 'dark_gray' },
[{ text: '', color: bot.colors.secondary }, username],
[{ text: '', ...bot.styles.secondary }, username],
{ text: ' ', color: 'dark_gray' },
message
], '@a')

View file

@ -14,7 +14,7 @@ function inject (bot, options) {
const startTime = Date.now()
bot.on('chat_html', async html => {
bot.on('chat_html', html => {
sendMessage(html)
})
@ -25,7 +25,7 @@ function inject (bot, options) {
contents: 'Click to copy the invite link for the Matrix space to your clipboard!'
},
clickEvent: {
action: 'copy_to_clipboard', // * Minecraft, and Java's URL class in general, seem to hate `#`, so open_url does not work.
action: 'copy_to_clipboard', // * Minecraft, and Java's URI class in general, seem to hate `#`, so open_url does not work.
value: bot.matrix.inviteUrl
}
}
@ -37,22 +37,6 @@ function inject (bot, options) {
const permissionLevel = event.sender.powerLevelNorm
let message = content.body
if (content.url) {
message = {
text: '[Attachment]',
color: bot.colors.primary,
clickEvent: {
action: 'open_url',
value: bot.matrix.client.mxcUrlToHttp(content.url)
}
}
} else if (message.startsWith(bot.matrix.commandPrefix)) {
const source = new CommandSource({ bot, permissionLevel, sendFeedback })
bot.commands.execute(message.substring(bot.matrix.commandPrefix.length), source)
return
}
const senderText = {
text: String(event.sender.rawDisplayName || event.sender.name || event.sender.userId),
hoverEvent: {
@ -64,6 +48,23 @@ function inject (bot, options) {
value: String(event.sender.userId)
}
}
if (content.url) {
message = {
text: '[Attachment]',
...bot.styles.primary,
clickEvent: {
action: 'open_url',
value: bot.matrix.client.mxcUrlToHttp(content.url)
}
}
} else if (message.startsWith(bot.matrix.commandPrefix)) {
const source = new CommandSource({ bot, permissionLevel, sendFeedback, displayName: senderText })
bot.commands.execute(message.substring(bot.matrix.commandPrefix.length), source)
return
}
bot.fancyMsg(matrixPrefix, senderText, message)
})

View file

@ -27,9 +27,9 @@ function inject (bot) {
setInterval(() => {
if (!bot.music.playing) return
const msg = [
{ text: 'Now Playing', color: bot.colors.primary },
{ text: 'Now Playing', ...bot.styles.primary },
{ text: ' | ', color: 'dark_gray' },
{ text: bot.music.nowPlaying.name, color: bot.colors.secondary, bold: true },
{ text: bot.music.nowPlaying.name, ...bot.styles.secondary, bold: true },
{ text: ' | ', color: 'dark_gray' },
format(bot.music.nowPlaying.time),
{ text: ' / ', color: 'gray' },
@ -40,7 +40,7 @@ function inject (bot) {
]
if (bot.music.looping) {
msg.push({ text: ' | ', color: 'dark_gray' })
msg.push({ text: 'Looping', color: bot.colors.secondary })
msg.push({ text: 'Looping', ...bot.styles.secondary })
}
bot.core.run('/title @a actionbar ' + JSON.stringify(msg))
}, 500)
@ -72,14 +72,14 @@ function inject (bot) {
song.time = 0
bot.music.nowPlaying = song
} catch (err) {
bot.core.run('minecraft:tellraw @a ' + JSON.stringify({ text: err.message, color: bot.colors.error }))
bot.core.run('minecraft:tellraw @a ' + JSON.stringify({ text: err.message, ...bot.styles.error }))
return
}
// play the music lol
bot.core.run(`/tellraw @a ${JSON.stringify([
{ text: 'Now playing ', color: bot.colors.primary },
{ text: song.name, color: bot.colors.secondary },
{ text: 'Now playing ', ...bot.styles.primary },
{ text: song.name, ...bot.styles.secondary },
'.'
])}`)
bot.music.playing = true

View file

@ -27,8 +27,8 @@ function inject (bot) {
if (seen[player.username].first == null) {
seen[player.username].first = new Date()
bot.core.run('minecraft:tellraw @a ' + JSON.stringify([
{ text: 'Welcome ', color: bot.colors.primary },
{ text: player.username, color: bot.colors.secondary },
{ text: 'Welcome ', ...bot.styles.primary },
{ text: player.username, ...bot.styles.secondary },
' to the server!'
]))
}

View file

@ -1,9 +0,0 @@
function inject (bot) {
function tellraw (text, target = '@a') {
bot.core.run(`minecraft:tellraw ${target} ${JSON.stringify(text)}`)
}
bot.tellraw = tellraw
}
module.exports = inject

30
plugins/utility.js Normal file
View file

@ -0,0 +1,30 @@
const fs = require('fs/promises')
function inject (bot) {
function tellraw (text, target = '@a') {
bot.core.run(`minecraft:tellraw ${target} ${JSON.stringify(text)}`)
}
async function listFiles (filepath, styling = {}) {
const list = await fs.readdir(filepath)
const msg = []
list.forEach((filename, idx) => {
if (idx !== 0) msg.push(' ')
const highlighting = !(idx & 1) ? bot.styles.secondary : bot.styles.primary
msg.push({
text: filename,
...highlighting,
...styling
})
})
return msg
}
bot.tellraw = tellraw
bot.listFiles = listFiles
}
module.exports = inject

0
songs/file 1 Normal file
View file

0
songs/file 2 Normal file
View file

0
songs/file 3 Normal file
View file

0
songs/file 4 Normal file
View file

0
songs/file 5 Normal file
View file

0
songs/file 6 Normal file
View file

0
songs/file 7 Normal file
View file

0
songs/file 8 Normal file
View file

0
songs/file 9 Normal file
View file

View file

@ -51,7 +51,7 @@ function htmlStringify (text, { lang = {} } = {}) {
if (text.color) {
const rgb = text.color[0] === '#' ? parseInt(text.color.substring(1), 16) : colormap[text.color]
if (rgb) string = `<font color="${rgb.toString(16).padStart(6, '0')}">${string}</font>`
if (rgb) string = `<font color="#${rgb.toString(16).padStart(6, '0')}">${string}</font>`
}
// formatting
@ -80,7 +80,7 @@ function preprocessText (input) {
const hex = colorcodemap[code]
if (hex) {
string += closing
string += `<font color="${hex}">`
string += `<font color="${hex.toString(16).padStart(6, '0')}">`
closing = '</font>'
continue
}

View file

@ -4,14 +4,23 @@ const formatNames = Object.fromEntries(formatting.map(format => [format.name, tr
const baseColors = colors.map(color => intToRgb(color.rgb))
function parseJsonText (json) {
return JSON.parse(json)
try {
return JSON.parse(json)
} catch {
return { text: '' }
}
}
function parseNbtText (data) {
if (typeof data.value !== 'object') return data.value
if (Array.isArray(data.value)) return [...data.value]
if (data.type === 'list') return data.value.value.map(value => parseNbtText({ value }))
return Object.fromEntries(Object.entries(data.value).map(([key, value]) => ([key === '' ? 'text' : key, parseNbtText(value)])))
try {
if (data.type === 'byte') return !!data.value
if (typeof data.value !== 'object') return data.value
if (Array.isArray(data.value)) return [...data.value]
if (data.type === 'list') return data.value.value.map(value => parseNbtText({ type: data.value.type, value }))
return Object.fromEntries(Object.entries(data.value).map(([key, value]) => ([key === '' ? 'text' : key, parseNbtText(value)])))
} catch {
return { text: '' }
}
}
function normalize (text) {

View file

@ -0,0 +1,48 @@
const { ArgumentType } = require('brigadier-commands')
const EXAMPLES = [123, -0.2, 'Hello, world!', true, false, { text: 'Hello, world!' }].map(v => JSON.stringify(v))
class JSONArgumentType extends ArgumentType {
static json () {
return new JSONArgumentType()
}
parse (reader) {
let string = ''
let depth = 0
let stringOpened = false
while (reader.canRead() && (depth !== 0 || reader.peek() !== ' ')) {
const c = reader.peek()
if (c === '\\') {
// Skip over escapes
let len = 2
if (reader.string[reader.cursor + 1] === 'u') len += 4
len = Math.max(len, reader.string.length - reader.cursor)
string += reader.string.substring(reader.cursor, reader.cursor + len)
reader.cursor += len
continue
}
if (c === '[' || c === '{') depth++
else if (c === ']' || c === '}') depth--
else if (c === '"') {
depth += stringOpened ? -1 : 1
stringOpened = !stringOpened
}
string += c
reader.skip()
}
return JSON.parse(string)
}
getExamples () {
return EXAMPLES
}
}
module.exports = JSONArgumentType

View file

@ -0,0 +1,63 @@
const { ArgumentType, SimpleCommandExceptionType, LiteralMessage } = require('brigadier-commands')
const path = require('path/posix')
const EXAMPLES = ['songs/amogus.mid', 'images/cat.jpg', 'videos/badapple.mp4']
const INVALID_URL_EXCEPTION = new SimpleCommandExceptionType(new LiteralMessage('Invalid URL'))
class LocationArgumentType extends ArgumentType {
constructor (allowPaths, allowUrls, root = '') {
super()
this.allowPaths = allowPaths
this.allowUrls = allowUrls
this.root = root
}
static location (root = '') { return new LocationArgumentType(true, true, root) }
static path (root = '') { return new LocationArgumentType(true, false, root) }
static url () { return new LocationArgumentType(false, true) }
parse (reader) {
const string = reader.readString()
if (this.allowUrls) {
if (string.startsWith('http://') || string.startsWith('https://')) {
return string
}
// TODO: Maybe support data URLs?
}
if (!this.allowPaths) {
throw INVALID_URL_EXCEPTION.create()
}
const root = path.resolve(this.root)
const splitPath = string.split(path.sep)
const sanitizedSplitPath = []
let depth = 0
for (const part of splitPath) {
if (part === '' || part === '.') continue
if (part === '..') {
if ((depth - 1) < 0) continue // Do not allow escaping the root directory
depth--
} else {
depth++
}
sanitizedSplitPath.push(part)
}
return [root, ...sanitizedSplitPath].join(path.sep)
}
static isUrl (string) {
return string.startsWith('http://') || string.startsWith('https://')
}
getExamples () {
return EXAMPLES
}
}
module.exports = LocationArgumentType

View file

@ -1,13 +1,14 @@
const { exceptions: { SimpleCommandExceptionType }, LiteralMessage } = require('brigadier-commands')
const { SimpleCommandExceptionType, LiteralMessage } = require('brigadier-commands')
const COMMAND_MUST_BE_EXECUTED_BY_A_PLAYER_EXCEPTION = new SimpleCommandExceptionType(new LiteralMessage('Command must be executed by a player')) // TODO: Translations
class CommandSource {
constructor ({ bot, player = null, permissionLevel = 0, sendFeedback = () => {} } = {}) {
constructor ({ bot, player = null, permissionLevel = 0, sendFeedback = () => {}, displayName = { text: '' } } = {}) {
this.bot = bot
this.player = player
this.permissionLevel = permissionLevel
this.sendFeedback = sendFeedback
this.displayName = displayName
}
sendError (error) {

26
util/command/utility.js Normal file
View file

@ -0,0 +1,26 @@
const nbt = require('prismarine-nbt')
const snbt = require('../snbt.js')
const toNbtUuid = require('../uuid-to-nbt-uuid.js')
function escapeString (input) {
let string = '"'
for (let i = 0; i < input.length; i++) {
const c = input[i]
if (c === '\\' || c === '"') string += '\\' + c
else string += c
}
string += '"'
return string
}
function createNameSelector (username) {
return `@a[limit=1,name=${escapeString(username)}]`
}
function createUuidSelector (uuid) {
return `@a[limit=1,nbt=${snbt.stringify(nbt.comp({ UUID: toNbtUuid(uuid) }))}]`
}
module.exports = { escapeString, createNameSelector, createUuidSelector }

View file

@ -6,7 +6,7 @@ const colorsys = require('colorsys')
async function convertImage (src, callback) {
const img = await canvas.loadImage(src).catch(callback)
if (!(img ?? false)) return
if (!img) return
ctx.drawImage(img, 0, 0, cnv.width, cnv.height)
const rgba = ctx.getImageData(0, 0, cnv.width, cnv.height).data
const lines = []