This commit is contained in:
u0_a342 2024-08-26 22:32:29 -04:00
commit af05ff16e9
36 changed files with 960 additions and 394 deletions

8
.gitignore vendored
View file

@ -154,3 +154,11 @@ settings.json
# Default secret file # Default secret file
secret.json secret.json
# botvX user settings
userPref/
# botvX log files
UBotLogs/
botvXLogs/
logs/

View file

@ -2,17 +2,13 @@
## What is it? ## What is it?
botvX is a Minecraft bot for [Kaboom](https://kaboom.pw/) and its clones. It has many of the features that you would expect in a modern Kaboom bot: botvX is a Minecraft bot originally designed for [Kaboom](https://kaboom.pw/) and its clones. It has many of the features that you would expect in a modern Kaboom bot:
- commands (obviously) - commands (obviously)
- a self care system - a self care system
- a command core, to run commands quickly - a command core, to run commands quickly
- a hashing system, to enable trusted users to securely run certain commands in chat - a hashing system, to enable trusted users to securely run certain commands in chat
## What does "botvX" mean?
"botvX" means "bot version 10". The v is used to signify that whatever after it is a version, as was done with previous versions (botv4, botv6, botv8, botv9), and the X is the Roman numeral for 10, since this is the 10th major version.
## How to install? ## How to install?
1. Install [Node.js](https://nodejs.org/) for your operating system. 1. Install [Node.js](https://nodejs.org/) for your operating system.

View file

@ -4,8 +4,9 @@ const { getMessage, formatTime } = require('../util/lang.js')
const fs = require('fs') const fs = require('fs')
const botVersion = require('../util/version.js') const botVersion = require('../util/version.js')
const version = require('../version.json') const version = require('../version.json')
const index = require('../index.js')
const aboutBot = function (c){ const aboutBot = function (c) {
c.reply({ c.reply({
translate: getMessage(c.lang, 'command.about.author'), translate: getMessage(c.lang, 'command.about.author'),
color: c.colors.secondary, color: c.colors.secondary,
@ -55,34 +56,34 @@ const aboutBot = function (c){
const os2 = function (o2, l) { const os2 = function (o2, l) {
switch (o2) { switch (o2) {
case 'win32': case 'win32':
return `${os.version()} (${os.release})` return `${os.version()}`
case 'android':{ case 'android':{
try { try {
const version = cp.execSync('getprop ro.build.version.release').toString('UTF-8').split('\n')[0] const version = cp.execSync('getprop ro.build.version.release').toString('UTF-8').split('\n')[0]
return getMessage(l, 'command.about.serverInfo.os.android', [version]) return getMessage(l, 'command.about.serverInfo.os.android', [version])
} catch(e){ } catch (e) {
getMessage(l, 'command.about.serverInfo.os.android.noVersion') return getMessage(l, 'command.about.serverInfo.os.android.noVersion')
} }
} }
case 'linux': case 'linux':
case 'freebsd':{ case 'freebsd':{
if(fs.readdirSync("/etc").includes("os-release")){ if (fs.readdirSync('/etc').includes('os-release')) {
const osrelease = fs.readFileSync('/etc/os-release').toString('UTF-8').split('\n') const osrelease = fs.readFileSync('/etc/os-release').toString('UTF-8').split('\n')
const osrelease2 = {} const osrelease2 = {}
for (const i in osrelease) { for (const item of osrelease) {
if (!osrelease[i].includes('=')) continue if (!item.includes('=')) continue
let osrvalue = osrelease[i].split('=')[1] let osrvalue = item.split('=')[1]
if (osrvalue.startsWith('"') && osrvalue.endsWith('"')) { osrvalue = osrvalue.slice(1, osrvalue.length - 1) }; if (osrvalue.startsWith('"') && osrvalue.endsWith('"')) { osrvalue = osrvalue.slice(1, osrvalue.length - 1) };
osrelease2[osrelease[i].split('=')[0]] = osrvalue osrelease2[item.split('=')[0]] = osrvalue
} }
if (osrelease2.PRETTY_NAME) { if (osrelease2.PRETTY_NAME) {
return getMessage(l, '%s %s', [osrelease2.PRETTY_NAME, os.release()]) return getMessage(l, '%s', [osrelease2.PRETTY_NAME])
} else { } else {
return getMessage(l, `command.about.serverInfo.os.${o2}`, [os.release()]) return getMessage(l, `command.about.serverInfo.os.${o2}`)
} }
} else { } else {
return getMessage(l, `command.about.serverInfo.os.${o2}`, [os.release()]) return getMessage(l, `command.about.serverInfo.os.${o2}`)
} }
} }
default: default:
@ -90,23 +91,41 @@ const os2 = function (o2, l) {
} }
} }
const aboutServer = function (c){ const aboutServer = function (c) {
const displayInfo = function (name, infoFunc) { const displayInfo = function (name, infoFunc) {
let thisItem; let thisItem
try { try {
thisItem = infoFunc() thisItem = infoFunc()
} catch(e) { } catch (e) {
console.error(e) console.error(e)
thisItem = "Error! (check console)" thisItem = 'Error! (check console)'
} }
c.reply({ c.reply({
translate: '%s: %s', translate: '%s: %s',
with:[ color: c.colors.primary,
with: [
{ {
text: getMessage(c.lang, name) text: getMessage(c.lang, name),
color: c.colors.secondary
}, },
{ {
text: thisItem text: thisItem,
color: c.colors.primary,
clickEvent: {
action: 'copy_to_clipboard',
value: thisItem
},
hoverEvent: {
action: 'show_text',
contents: {
text: getMessage(c.lang, 'copyText'),
color: c.colors.secondary
},
value: { // Added twice for backwards compatibility
text: getMessage(c.lang, 'copyText'),
color: c.colors.secondary
}
}
} }
] ]
}) })
@ -117,14 +136,19 @@ const aboutServer = function (c){
return os2(process.platform, c.lang) return os2(process.platform, c.lang)
}) })
// Kernel version: os.release()
displayInfo('command.about.serverInfo.kernelVer', () => {
return os.release()
})
// Processor // Processor
if (os.cpus()[0]){ if (os.cpus()[0]) {
displayInfo('command.about.serverInfo.processor', () => { displayInfo('command.about.serverInfo.processor', () => {
return os.cpus()[0].model return os.cpus()[0].model
}) })
} }
if (os.cpus()[0]){ if (os.cpus()[0]) {
// Processor architecture // Processor architecture
displayInfo('command.about.serverInfo.arch', () => { displayInfo('command.about.serverInfo.arch', () => {
return os.machine() return os.machine()
@ -161,13 +185,12 @@ const aboutServer = function (c){
return formatTime(os.uptime() * 1000, c.lang) return formatTime(os.uptime() * 1000, c.lang)
}) })
if (process.platform === 'android') { if (process.platform === 'android') {
// Device model // Device model
displayInfo('command.about.serverInfo.os.android.model', () => { displayInfo('command.about.serverInfo.os.android.model', () => {
const dModel = cp.execSync('getprop ro.product.model').toString('UTF-8').split('\n')[0] const brand = cp.execSync('getprop ro.product.brand').toString('UTF-8').split('\n')[0]
const dBrand = cp.execSync('getprop ro.product.brand').toString('UTF-8').split('\n')[0] const model = cp.execSync('getprop ro.product.model').toString('UTF-8').split('\n')[0]
return `${dBrand} ${dModel}` return `${brand} ${model}`
}) })
} }
@ -175,15 +198,58 @@ const aboutServer = function (c){
displayInfo('command.about.serverInfo.botVer', () => { displayInfo('command.about.serverInfo.botVer', () => {
return botVersion return botVersion
}) })
} }
const displayServerList = function (c) {
index.bot.forEach((item, i) => {
if (item.host.options && item.host.options.hidden && c.verify !== 3 && c.bot.id !== i) return
let message = 'command.about.serverListItem'
if (c.bot.id === i) message = 'command.about.serverListItem.thisServer'
c.reply({
translate: getMessage(c.lang, message),
color: c.colors.secondary,
with: [
{
text: i.toString(),
color: c.colors.primary
},
{
text: `${item.host.host}:${item.host.port}`,
color: c.colors.primary,
clickEvent: {
action: 'copy_to_clipboard',
value: `${item.host.host}:${item.host.port}`
},
hoverEvent: {
action: 'show_text',
contents: {
text: getMessage(c.lang, 'copyText'),
color: c.colors.secondary
},
value: { // Added twice for backwards compatibility
text: getMessage(c.lang, 'copyText'),
color: c.colors.secondary
}
}
}
]
})
})
}
module.exports = { module.exports = {
execute: function (c) { execute: function (c) {
if(c.args[0] === 'server'){ let subcmd = c.args[0]
if (subcmd === 'servers') subcmd = 'serverlist'
if (c.cmdName === 'serverinfo') subcmd = 'server'
if (c.cmdName === 'serverlist' || c.cmdName === 'servers') subcmd = 'serverlist'
if (subcmd === 'server') {
aboutServer(c) aboutServer(c)
} else if (subcmd === 'serverlist') {
displayServerList(c)
} else { } else {
aboutBot(c) aboutBot(c)
} }
}, },
aliases: ['info'] aliases: ['info', 'serverlist', 'servers', 'serverinfo']
} }

View file

@ -44,26 +44,26 @@ module.exports = {
break break
} }
case 'list': case 'list':
for (const i in c.bot.cloops) { c.bot.cloops.forEach((item, i) => {
c.reply({ c.reply({
translate: getMessage(c.lang, 'command.cloop.list'), translate: getMessage(c.lang, 'command.cloop.list'),
color: c.colors.secondary, color: c.colors.secondary,
with: [ with: [
{ {
text: i, text: i.toString(),
color: c.colors.primary color: c.colors.primary
}, },
{ {
text: c.bot.cloops[i].command, text: item.command,
color: c.colors.primary color: c.colors.primary
}, },
{ {
text: c.bot.cloops[i].rate + '', text: item.rate + '',
color: c.colors.primary color: c.colors.primary
} }
] ]
}) })
} })
break break
case 'clear': case 'clear':
c.bot.clearCloops() c.bot.clearCloops()

View file

@ -9,14 +9,14 @@ const sortHelp = function sortHelp (c1, c2) {
} }
const bpl = fs.readdirSync('./commands') const bpl = fs.readdirSync('./commands')
for (const i in bpl) { // Built-in loadCMD to the help command, to prevent circular require for (const plugin of bpl) {
if (!bpl[i].endsWith('.js')) { if (!plugin.endsWith('.js')) {
continue continue
} }
try { try {
const commandName = bpl[i].split('.js')[0] const commandName = plugin.split('.js')[0]
if (commandName !== 'help') { if (commandName !== 'help') {
cmds[commandName] = require(`./${bpl[i]}`) cmds[commandName] = require(`./${plugin}`)
if (cmds[commandName].level === undefined) { if (cmds[commandName].level === undefined) {
cmds[commandName].level = 0 cmds[commandName].level = 0
} }
@ -66,7 +66,7 @@ const printHelp = (c) => {
const printCmdHelp = (c) => { const printCmdHelp = (c) => {
const cmd = c.args[0] const cmd = c.args[0]
if (!cmds[cmd]) { if (!cmds[cmd] || (cmds[cmd].hidden && c.type !== 'console')) {
c.reply({ text: getMessage(c.lang, 'command.help.noCommand') }) c.reply({ text: getMessage(c.lang, 'command.help.noCommand') })
return return
} }
@ -81,7 +81,7 @@ const printCmdHelp = (c) => {
if (cmds[cmd].alias) { if (cmds[cmd].alias) {
console.log(cmds[cmds[cmd].alias]) console.log(cmds[cmds[cmd].alias])
usage = getMessage(c.lang, `command.${cmds[cmd].alias}.usage`).split('||') usage = getMessage(c.lang, `command.${cmds[cmd].alias}.usage`).split('||')
desc = getMessage(c.lang, `command.help.alias`, [cmds[cmd].alias]) desc = getMessage(c.lang, 'command.help.alias', [cmds[cmd].alias])
if (cmds[cmds[cmd].alias].usage) { if (cmds[cmds[cmd].alias].usage) {
usage = cmds[cmds[cmd].alias].usage.split('||') usage = cmds[cmds[cmd].alias].usage.split('||')
} }
@ -89,7 +89,7 @@ const printCmdHelp = (c) => {
desc = cmds[cmds[cmd].alias].desc desc = cmds[cmds[cmd].alias].desc
} }
} }
for (const i in usage) { for (const item of usage) {
c.reply({ c.reply({
translate: getMessage(c.lang, 'command.help.commandUsage'), translate: getMessage(c.lang, 'command.help.commandUsage'),
color: c.colors.secondary, color: c.colors.secondary,
@ -99,7 +99,7 @@ const printCmdHelp = (c) => {
color: c.colors.primary color: c.colors.primary
}, },
{ {
text: usage[i], text: item,
color: c.colors.primary color: c.colors.primary
} }
] ]
@ -152,8 +152,8 @@ if (cmds.help.level === undefined) {
for (const i in cmds) { for (const i in cmds) {
if (cmds[i].aliases) { if (cmds[i].aliases) {
for (const j in cmds[i].aliases) { for (const alias of cmds[i].aliases) {
cmds[cmds[i].aliases[j]] = { cmds[alias] = {
alias: i, alias: i,
usage: cmds[i].usage, usage: cmds[i].usage,
level: cmds[i].level, level: cmds[i].level,

View file

@ -1,22 +1,40 @@
const { bot } = require('../index.js') const { bot } = require('../index.js')
const { getMessage } = require('../util/lang.js')
module.exports = { module.exports = {
execute: (c) => { execute: (c) => {
let host = c.host
let port = c.port
if (c.bot.host.options && c.bot.host.options.hidden) {
host = 'localhost' // Makes hidden servers appear as localhost
port = '25565'
}
const json = { const json = {
translate: '[%s] %s: %s', translate: '[%s] %s: %s',
with: [ with: [
{ {
translate: '%s:%s', text: c.serverName,
with: [ hoverEvent: {
{ action: 'show_text',
text: c.host, value: {
color: c.colors.primary translate: '%s: %s:%s',
}, with: [
{ {
text: c.port + '', text: getMessage(c.lang, 'command.netmsg.serverAddress'),
color: c.colors.primary color: c.colors.primary
},
{
text: host,
color: c.colors.primary
},
{
text: port + '',
color: c.colors.primary
}
],
color: c.colors.secondary
} }
], },
color: c.colors.secondary color: c.colors.primary
}, },
{ {
text: c.username, text: c.username,
@ -28,8 +46,9 @@ module.exports = {
], ],
color: 'white' color: 'white'
} }
for (const i in bot) { bot.forEach(item => {
bot[i].tellraw('@a', json) if (item.host.options && item.host.options.netmsgIncomingDisabled && c.type !== 'console') return
} item.tellraw('@a', json)
})
} }
} }

155
commands/settings.js Normal file
View file

@ -0,0 +1,155 @@
const { languages, getMessage } = require('../util/lang.js')
const fs = require('fs')
const settings = require('../settings.json')
module.exports = {
execute: (c) => {
if (c.type === 'console') {
c.reply({
text: getMessage(c.lang, 'command.settings.disabled.console'),
color: c.colors.secondary
})
return
}
if (settings.userSettingsDisabled) {
c.reply({
text: getMessage(c.lang, 'command.settings.disabled.global'),
color: c.colors.secondary
})
return
}
const subcmd = c.args.splice(0, 1)[0]
switch (subcmd) {
case 'set':{
const allowedKeys = ['colorPrimary', 'colorSecondary', 'lang']
const key = c.args.splice(0, 1)[0]
if (!allowedKeys.includes(key)) {
c.reply({
text: getMessage(c.lang, 'command.settings.error.invalidKey'),
color: c.colors.secondary
})
return
}
const value = c.args.join(' ')
if (value === '' && key === 'lang') {
// Show all valid languages to user
for (const item of languages) {
c.reply({
translate: '%s (%s)',
color: c.colors.secondary,
with: [
{
text: getMessage(item, 'language.name'),
color: c.colors.primary
},
{
text: getMessage(item, 'language.region'),
color: c.colors.primary
}
],
hoverEvent: {
action: 'show_text',
value: {
translate: getMessage(item, 'command.settings.setLanguage'),
with: [
{
text: `${c.prefix}settings set lang ${item}`,
color: c.colors.secondary
}
]
}
}
})
}
return
}
if (value === '') {
c.reply({
text: getMessage(c.lang, 'command.settings.error.mustProvideValue'),
color: c.colors.secondary
})
return
}
if (key === 'lang' && !languages.includes(value)) {
c.reply({
text: getMessage(c.lang, 'command.settings.error.invalidLanguage'),
color: c.colors.secondary
})
return
}
c.prefs[key] = value
// Save to file
fs.writeFileSync(`userPref/${c.uuid}.json`, JSON.stringify(c.prefs))
// Delete require cache
for (const i in require.cache) {
if (i.endsWith(`${c.uuid}.json`)) delete require.cache[i]
}
c.reply({
text: getMessage(c.lang, 'command.settings.saved'),
color: c.colors.secondary
})
break
}
case 'get':
c.reply({
translate: '%s: %s',
color: c.colors.primary,
with: [
{
text: getMessage(c.lang, 'command.settings.get.colorPrimary'),
color: c.colors.secondary
},
{
text: c.colors.primary,
color: c.colors.primary
}
]
})
c.reply({
translate: '%s: %s',
color: c.colors.primary,
with: [
{
text: getMessage(c.lang, 'command.settings.get.colorSecondary'),
color: c.colors.secondary
},
{
text: c.colors.secondary,
color: c.colors.secondary
}
]
})
c.reply({
translate: '%s: %s (%s)',
color: c.colors.primary,
with: [
{
text: getMessage(c.lang, 'command.settings.get.language'),
color: c.colors.secondary
},
{
text: getMessage(c.lang, 'language.name'),
color: c.colors.primary
},
{
text: getMessage(c.lang, 'language.region'),
color: c.colors.primary
}
]
})
break
default:
c.reply({
translate: getMessage(c.lang, 'command.cloop.error.subcommand'),
color: c.colors.secondary,
with: [
{
text: `${c.prefix}help settings`,
color: c.colors.primary
}
]
})
}
}
}

View file

@ -37,6 +37,6 @@ module.exports = {
*/ */
hidden: true, // To show the command on the help command list, remove this line (optional) hidden: true, // To show the command on the help command list, remove this line (optional)
consoleIndex: true, // When run from console, the second argument will be a bot ID (optional) consoleIndex: true, // When run from console, the second argument will be a bot ID (optional)
aliases: ['example', 'testing'], // Other command names that will work the same (optional) aliases: ['example'], // Other command names that will work the same (optional)
level: 0 // Permission level required to run this command (optional) level: 0 // Permission level required to run this command (optional)
} }

49
commands/test.js Normal file
View file

@ -0,0 +1,49 @@
const { getMessage } = require('../util/lang.js')
module.exports = {
execute: (c) => {
const reply = function (name, item) {
return {
translate: '%s: %s',
color: c.colors.primary,
with: [
{
text: getMessage(c.lang, `command.test.${name}`),
color: c.colors.secondary
},
{
text: item,
color: c.colors.primary,
clickEvent: {
action: 'copy_to_clipboard',
value: item
},
hoverEvent: {
action: 'show_text',
contents: {
text: getMessage(c.lang, 'copyText'),
color: c.colors.secondary
},
value: { // Added twice for backwards compatibility
text: getMessage(c.lang, 'copyText'),
color: c.colors.secondary
}
}
}
]
}
}
c.reply(reply('uuid', c.uuid))
c.reply(reply('username', c.username))
c.reply(reply('nickname', c.nickname))
c.reply(reply('command', c.command))
c.reply(reply('msgType', c.msgType))
c.reply(reply('prefix', c.prefix))
c.reply(reply('args', c.args.join(', ')))
c.reply(reply('verify', c.verify.toString()))
c.reply(reply('host', c.host))
c.reply(reply('port', c.port.toString()))
c.reply(reply('lang', c.lang))
c.reply(reply('colorPrimary', c.colors.primary))
c.reply(reply('colorSecondary', c.colors.secondary))
}
}

View file

@ -16,6 +16,6 @@ module.exports = {
] ]
}) })
}, },
aliases: ['validate'], aliases: ['verify'],
level: 1 level: 1
} }

View file

@ -1,22 +1,34 @@
const m = require('minecraft-protocol')
const settings = require('./settings.json')
const generateUser = require('./util/usergen.js')
const EventEmitter = require('node:events')
const fs = require('fs') const fs = require('fs')
if (!fs.readdirSync('.').includes('settings.json')) {
console.log('Settings file is missing, using defaults.')
fs.copyFileSync('settings_example.json', 'settings.json')
}
if (!fs.readdirSync('.').includes('secret.json')) {
console.log('Secrets file is missing, using defaults.')
fs.copyFileSync('secret_example.json', 'secret.json')
console.log('Please change the hashing keys in the secrets file.')
}
const m = require('minecraft-protocol')
const generateUser = require('./util/usergen.js')
const EventEmitter = require('node:events')
const settings = require('./settings.json')
module.exports.bot = [] module.exports.bot = []
const loadplug = (botno) => { const botplug = []
const botplug = [] const bpl = fs.readdirSync('plugins')
const bpl = fs.readdirSync('plugins') for (const plugin of bpl) {
for (const i in bpl) { if (!plugin.endsWith('.js')) {
if (!bpl[i].endsWith('.js')) { continue
continue
}
try {
botplug.push(require(`./plugins/${bpl[i]}`))
} catch (e) { console.log(e) }
} }
try {
botplug.push(require(`./plugins/${plugin}`))
} catch (e) { console.log(e) }
}
const loadplug = (botno) => {
botplug.forEach((plug) => { botplug.forEach((plug) => {
try { try {
if (plug.load) { if (plug.load) {
@ -66,8 +78,8 @@ const createBot = function createBot (host, oldId) {
}) })
} }
for (const i in settings.servers) { for (const server of settings.servers) {
createBot(settings.servers[i]) createBot(server)
} }
module.exports.createBot = createBot module.exports.createBot = createBot

View file

@ -1,4 +1,6 @@
{ {
"language.name": "English",
"language.region": "United States",
"time.week": " week ", "time.week": " week ",
"time.weekPlural": " weeks ", "time.weekPlural": " weeks ",
"time.day": " day ", "time.day": " day ",
@ -9,6 +11,7 @@
"time.minutePlural": " minutes ", "time.minutePlural": " minutes ",
"time.second": " second ", "time.second": " second ",
"time.secondPlural": " seconds ", "time.secondPlural": " seconds ",
"chat.antiSpamTriggered": "Anti-spam has been triggered for this server.",
"command.about.usage": "", "command.about.usage": "",
"command.about.desc": "About the bot", "command.about.desc": "About the bot",
"command.cb.usage": " <command>", "command.cb.usage": " <command>",
@ -27,17 +30,21 @@
"command.refill.desc": "Refill core", "command.refill.desc": "Refill core",
"command.say.usage": " <message>", "command.say.usage": " <message>",
"command.say.desc": "Sends a message to chat", "command.say.desc": "Sends a message to chat",
"command.settings.usage": " get|| set <key> <value>",
"command.settings.desc": "Set your user preferences",
"command.stop.usage": "", "command.stop.usage": "",
"command.stop.desc": "Restart bot", "command.stop.desc": "Restart bot",
"command.template.usage": " <required> [optional]", "command.template.usage": " <required> [optional]",
"command.template.desc": "Does nothing", "command.template.desc": "Does nothing",
"command.tpr.desc": "Teleport to a random location", "command.test.usage": " [args...]",
"command.test.desc": "Chat parsing debugger command",
"command.tpr.usage": "", "command.tpr.usage": "",
"command.tpr.desc": "Teleport to a random location",
"command.verify.usage": " [args...]", "command.verify.usage": " [args...]",
"command.verify.desc": "Check the hashing system", "command.verify.desc": "Check the hashing system",
"command.about.author": "%s - a Minecraft bot made by %s for Kaboom and clones", "command.about.author": "%s - a Minecraft bot made by %s for Kaboom and clones",
"command.about.version": "Version %s", "command.about.version": "Version %s",
"command.about.preRelease": "This is prerelease software - there may be errors, and features may be changed or removed at any time.", "command.about.preRelease": "This is a development version - there may be errors, and features may be changed or removed at any time. Please report any errors to the bot's developer.",
"command.about.sourceCode": "Source code: %s", "command.about.sourceCode": "Source code: %s",
"command.about.sourceCode.openInBrowser": "Click to open the source code link in your default browser", "command.about.sourceCode.openInBrowser": "Click to open the source code link in your default browser",
"command.cloop.error.tooShort": "Command loops must have a rate above 20ms.", "command.cloop.error.tooShort": "Command loops must have a rate above 20ms.",
@ -57,14 +64,38 @@
"command.help.permsConsole": "Console", "command.help.permsConsole": "Console",
"command.help.noCommand": "Command does not exist", "command.help.noCommand": "Command does not exist",
"command.help.alias": "Alias to %s", "command.help.alias": "Alias to %s",
"command.serverinfo.deprecated": "The legacy version 9 serverinfo command will be removed in the future. The command's features will be merged with the \"about\" command as \"about server\" (or an alias).", "command.netmsg.disabled": "This command has been disabled on this server.",
"command.netmsg.serverAddress": "Server Address",
"command.settings.disabled.console": "This command cannot be run from the console.",
"command.settings.get.colorPrimary": "Primary color",
"command.settings.get.colorSecondary": "Secondary color",
"command.settings.get.language": "Language",
"command.settings.setLanguage": "Run %s to set this as your language",
"command.settings.error.invalidKey": "Invalid key",
"command.settings.error.invalidLanguage": "Invalid language",
"command.settings.error.mustProvideValue": "You must provide a value",
"command.settings.saved": "Settings saved.",
"command.test.uuid": "UUID",
"command.test.username": "Username",
"command.test.nickname": "Nickname",
"command.test.command": "Command",
"command.test.msgType": "Message type",
"command.test.prefix": "Prefix",
"command.test.args": "Arguments",
"command.test.verify": "Permission level",
"command.test.host": "Server host",
"command.test.port": "Server port",
"command.test.lang": "Language",
"command.test.colorPrimary": "Primary color",
"command.test.colorSecondary": "Secondary color",
"command.about.serverInfo.os.android": "Android %s", "command.about.serverInfo.os.android": "Android %s",
"command.about.serverInfo.os.android.noVersion": "Android", "command.about.serverInfo.os.android.noVersion": "Android",
"command.about.serverInfo.os.freebsd": "FreeBSD %s", "command.about.serverInfo.os.freebsd": "FreeBSD",
"command.about.serverInfo.os.linux": "Linux %s", "command.about.serverInfo.os.linux": "Linux",
"command.about.serverInfo.os.macos": "macOS", "command.about.serverInfo.os.macos": "macOS",
"command.about.serverInfo.os.macos_old": "OS X", "command.about.serverInfo.os.macos_old": "OS X",
"command.about.serverInfo.os": "Operating system", "command.about.serverInfo.os": "Operating system",
"command.about.serverInfo.kernelVer": "Kernel version",
"command.about.serverInfo.processor": "CPU", "command.about.serverInfo.processor": "CPU",
"command.about.serverInfo.arch": "Architecture", "command.about.serverInfo.arch": "Architecture",
"command.about.serverInfo.osUsername": "Username", "command.about.serverInfo.osUsername": "Username",
@ -79,6 +110,8 @@
"command.about.serverInfo.os.android.model": "Device model", "command.about.serverInfo.os.android.model": "Device model",
"command.about.serverInfo.botName": "Bot name", "command.about.serverInfo.botName": "Bot name",
"command.about.serverInfo.botVer": "Bot version", "command.about.serverInfo.botVer": "Bot version",
"command.about.serverListItem": "Server %s - %s",
"command.about.serverListItem.thisServer": "Server %s - %s (this server)",
"command.tpr.success": "Teleporting %s to %s, %s, %s", "command.tpr.success": "Teleporting %s to %s, %s, %s",
"command.verify.success": "Successfully verified with permission level %s", "command.verify.success": "Successfully verified with permission level %s",
"command.error": "An error occured (check console for more info)", "command.error": "An error occured (check console for more info)",

36
package-lock.json generated
View file

@ -7,28 +7,28 @@
"": { "": {
"name": "botv10", "name": "botv10",
"version": "10.0.0", "version": "10.0.0",
"license": "UNLICENSED", "license": "MIT",
"dependencies": { "dependencies": {
"minecraft-protocol": "^1.45.0", "minecraft-protocol": "^1.45.0",
"prismarine-chat": "^1.10.0" "prismarine-chat": "^1.10.0"
} }
}, },
"node_modules/@azure/msal-common": { "node_modules/@azure/msal-common": {
"version": "14.14.0", "version": "14.14.1",
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.14.0.tgz", "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.14.1.tgz",
"integrity": "sha512-OxcOk9H1/1fktHh6//VCORgSNJc2dCQObTm6JNmL824Z6iZSO6eFo/Bttxe0hETn9B+cr7gDouTQtsRq3YPuSQ==", "integrity": "sha512-2Q3tqNz/PZLfSr8BvcHZVpRRfSn4MjGSqjj9J+HlBsmbf1Uu4P0WeXnemjTJwwx9KrmplsrN3UkZ/LPOR720rw==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
} }
}, },
"node_modules/@azure/msal-node": { "node_modules/@azure/msal-node": {
"version": "2.12.0", "version": "2.13.0",
"resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.12.0.tgz", "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.13.0.tgz",
"integrity": "sha512-jmk5Im5KujRA2AcyCb0awA3buV8niSrwXZs+NBJWIvxOz76RvNlusGIqi43A0h45BPUy93Qb+CPdpJn82NFTIg==", "integrity": "sha512-DhP97ycs7qlCVzzzWGzJiwAFyFj5okno74E4FUZ61oCLfKh4IxA1kxirqzrWuYZWpBe9HVPL6GA4NvmlEOBN5Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@azure/msal-common": "14.14.0", "@azure/msal-common": "14.14.1",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"uuid": "^8.3.0" "uuid": "^8.3.0"
}, },
@ -37,12 +37,12 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.1.0", "version": "22.5.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz",
"integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~6.13.0" "undici-types": "~6.19.2"
} }
}, },
"node_modules/@types/readable-stream": { "node_modules/@types/readable-stream": {
@ -427,9 +427,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/minecraft-data": { "node_modules/minecraft-data": {
"version": "3.67.0", "version": "3.68.0",
"resolved": "https://registry.npmjs.org/minecraft-data/-/minecraft-data-3.67.0.tgz", "resolved": "https://registry.npmjs.org/minecraft-data/-/minecraft-data-3.68.0.tgz",
"integrity": "sha512-/hLeYXopx9o1UdViPPFenLJ3hT5S4qUEwLQM0MAHOIhqkAUGXdkl47O7ohG+f87DH3+cZksbbM61sTnSRsQpsA==", "integrity": "sha512-pNBTi39a1zbFpN9itwi0YSL3hqAsSw38D7pE9C6m+aURmXljpBlNTO+TkpZxxDv4KqqtNBOhmkj4x46IDW6R+Q==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/minecraft-folder-path": { "node_modules/minecraft-folder-path": {
@ -762,9 +762,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "6.13.0", "version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/uri-js": { "node_modules/uri-js": {

View file

@ -10,6 +10,6 @@
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"author": "", "author": "",
"license": "UNLICENSED", "license": "MIT",
"description": "" "description": ""
} }

View file

@ -1,97 +1,118 @@
const settings = require('../settings.json') const settings = require('../settings.json')
const parsePlain = require('../util/chatparse_plain.js') const parsePlain = require('../util/chatparse_plain.js')
const parseConsole = require('../util/chatparse_console.js') const parseConsole = require('../util/chatparse_console.js')
const parse1204 = require('../util/chatparse_1204.js') const parse1204 = require('../util/parseNBT.js')
const messageTypes = [ const { getMessage } = require('../util/lang.js')
'', const convertChatStyleItem = (item) => {
'chat.type.emote', const output = {}
'commands.message.display.incoming', for (const i in item) {
'commands.message.display.outgoing', output[i] = item[i].value
'', }
'chat.type.announcement', return output
'chat.type.team.text', }
'chat.type.team.sent' const convertChatTypeItem = (item) => {
] if (item.style) {
return {
translation_key: item.translation_key.value,
parameters: item.parameters.value.value,
style: convertChatStyleItem(item.style.value)
}
} else {
return {
translation_key: item.translation_key.value,
parameters: item.parameters.value.value,
style: {}
}
}
}
module.exports = { module.exports = {
load: (b) => { load: (b) => {
b._client.on('profileless_chat', (data) => { b.messageCount = 0
if (data.type === 4) { b.chatDisabledUntil = 0
const json = parse1204(data.message) b.interval.antiSpam = setInterval(() => {
const parsed = parsePlain(json) b.messageCount = 0
const split = parsed.split(': ') }, 4000)
const chatName = split.splice(0, 1)[0] b.messageTypes = []
const username = b.findRealName(chatName) b._client.on('registry_data', (data) => {
const uuid = b.findUUID(username) if (data.codec.value['minecraft:chat_type']) {
b.emit('chat', { json, type: 'profileless', uuid, message: split.join(': '), username }) b.messageTypes = data.codec.value['minecraft:chat_type']
} else if (data.type === 6 || data.type === 7) { const nbtItems = data.codec.value['minecraft:chat_type'].value.value.value.value
b.emit('chat', { nbtItems.forEach((item, i) => {
json: { b.messageTypes[i] = convertChatTypeItem(item.element.value.chat.value)
translate: messageTypes[data.type],
color: (data.type === 2 || data.type === 3) ? 'gray' : 'reset',
with: [
parse1204(data.target),
parse1204(data.name),
data.message
]
},
type: 'profileless',
uuid: data.senderUuid,
message: parsePlain(data.message),
username: parsePlain(parse1204(data.name))
})
} else {
b.emit('chat', {
json: {
translate: messageTypes[data.type],
color: (data.type === 2 || data.type === 3) ? 'gray' : 'reset',
with: [
parse1204(data.name),
parse1204(data.message)
]
},
type: 'profileless',
uuid: '00000000-0000-0000-0000-000000000000',
message: parsePlain(parse1204(data.message)),
username: parsePlain(parse1204(data.name))
}) })
} }
}) })
b._client.on('profileless_chat', (data) => {
const messageType = b.messageTypes[data.type]
const json = { translate: messageType.translation_key, with: [] }
messageType.parameters.forEach((item, i) => {
if (item === 'content') {
json.with[i] = parse1204(data.message)
} else if (item === 'sender') {
json.with[i] = parse1204(data.name)
} else if (item === 'target') {
json.with[i] = parse1204(data.target)
}
})
for (const i in messageType.style) {
json[i] = messageType.style[i]
}
let username = ''
let nickname = ''
let uuid = '00000000-0000-0000-0000-000000000000'
let message = ''
if (messageType.translation_key === '%s') {
const parsed = parsePlain(json)
const split = parsed.split(': ')
const chatName = split.splice(0, 1)[0]
const chatNameSplit = chatName.split(' ')
nickname = chatNameSplit[chatNameSplit.length - 1]
username = b.findRealName(chatName)
uuid = b.findUUID(username)
message = split.join(': ')
} else {
message = parsePlain(parse1204(data.message))
uuid = b.findUUID(parsePlain(parse1204(data.name)))
nickname = b.findDisplayName(uuid)
username = parsePlain(parse1204(data.name))
}
b.emit('chat', {
json,
type: 'profileless',
uuid,
message,
nickname,
username
})
})
b._client.on('player_chat', (data) => { b._client.on('player_chat', (data) => {
if (data.type === 4) { const messageType = b.messageTypes[data.type]
b.emit('chat', { json: parse1204(data.unsignedChatContent), type: 'player', uuid: data.senderUuid, message: data.plainMessage, username: parsePlain(parse1204(data.networkName)) }) const json = { translate: messageType.translation_key, with: [] }
} else if (data.type === 6 || data.type === 7) { messageType.parameters.forEach((item, i) => {
b.emit('chat', { if (item === 'content') {
json: { if (messageType.translation_key === '%s') {
translate: messageTypes[data.type], json.with[i] = parse1204(data.unsignedChatContent)
color: data.type === 2 ? 'gray' : 'reset', } else {
with: [ json.with[i] = data.plainMessage
parse1204(data.networkTargetName), }
parse1204(data.networkName), } else if (item === 'sender') {
data.plainMessage json.with[i] = parse1204(data.networkName)
] } else if (item === 'target') {
}, json.with[i] = parse1204(data.networkTargetName)
type: 'player', }
uuid: data.senderUuid, })
message: parsePlain(data.plainMessage), for (const i in messageType.style) {
username: parsePlain(parse1204(data.networkName)) json[i] = messageType.style[i]
})
} else {
b.emit('chat', {
json: {
translate: messageTypes[data.type],
color: (data.type === 2 || data.type === 3) ? 'gray' : 'reset',
with: [
parse1204(data.networkName),
data.plainMessage
]
},
type: 'player',
uuid: data.senderUuid,
message: parsePlain(data.plainMessage),
username: parsePlain(parse1204(data.networkName))
})
} }
b.emit('chat', {
json,
type: 'player',
uuid: data.senderUuid,
message: data.plainMessage,
nickname: parsePlain(parse1204(data.networkName)),
username: b.findRealNameFromUUID(data.senderUuid)
})
}) })
b._client.on('system_chat', (data) => { b._client.on('system_chat', (data) => {
@ -99,15 +120,25 @@ module.exports = {
const parsed = parsePlain(json) const parsed = parsePlain(json)
const split = parsed.split(': ') const split = parsed.split(': ')
const chatName = split.splice(0, 1)[0] const chatName = split.splice(0, 1)[0]
const chatNameSplit = chatName.split(' ')
const nickname = chatNameSplit[chatNameSplit.length - 1]
const username = b.findRealName(chatName) const username = b.findRealName(chatName)
const uuid = b.findUUID(username) const uuid = b.findUUID(username)
b.emit('chat', { json, type: 'system', uuid, message: split.join(': '), username }) b.emit('chat', {
json,
type: 'system',
uuid,
message: split.join(': '),
nickname,
username
})
}) })
b._client.on('chat', (data) => { // Legacy chat b._client.on('chat', (data) => { // Legacy chat for versions <1.19
const json = parse1204(data.message) const json = parse1204(data.message)
const parsed = parsePlain(json) const parsed = parsePlain(json)
let chatName let chatName
let nickname
let username let username
let message let message
let uuid let uuid
@ -119,30 +150,39 @@ module.exports = {
uuid = b.findUUID(username) uuid = b.findUUID(username)
} else { // Servers with Extras chat, such as Kaboom } else { // Servers with Extras chat, such as Kaboom
const split = parsed.split(': ') const split = parsed.split(': ')
message = split.join(': ')
uuid = b.findUUID(username)
chatName = split.splice(0, 1)[0] chatName = split.splice(0, 1)[0]
const chatNameSplit = chatName.split(' ')
nickname = chatNameSplit[chatNameSplit.length - 1]
username = b.findRealName(chatName) username = b.findRealName(chatName)
uuid = b.findUUID(username)
message = split.join(': ')
} }
b.emit('chat', { json, type: 'legacy', uuid: data.uuid ? data.uuid : uuid, message, username }) if (data.uuid) uuid = data.uuid
b.emit('chat', {
json,
type: 'legacy',
uuid,
message,
nickname,
username
})
}) })
b.on('chat', (data) => { b.on('chat', (data) => {
b.messageCount++
if (Date.now() < b.chatDisabledUntil) return
if (b.messageCount >= 100) {
b.info(getMessage(settings.defaultLang, 'chat.antiSpamTriggered'))
b.chatDisabledUntil = Date.now() + 30000
return
}
const msgConsole = parseConsole(data.json) const msgConsole = parseConsole(data.json)
const msgPlain = parsePlain(data.json) const msgPlain = parsePlain(data.json)
if (settings.logJSONmessages) console.log(data.json) if (settings.logJSONmessages) console.log(data.json)
if (msgPlain.endsWith('\n\n\n\n\nThe chat has been cleared')) return if (msgPlain.endsWith('\n\n\n\n\nThe chat has been cleared')) return
if (msgPlain.startsWith('Command set: ')) return if (msgPlain.startsWith('Command set: ')) return
b.emit('plainchat', msgPlain) b.emit('plainchat', msgPlain, data.type)
b.displayChat(data.type, `${msgConsole}\x1b[0m`) b.displayChat(data.type, `${msgConsole}\x1b[0m`)
const fullCommand = data.message
for (const i in b.prefix) {
if (fullCommand.startsWith(b.prefix[i])) {
const command = fullCommand.slice(b.prefix[i].length)
b.runCommand(data.username, data.uuid, command, b.prefix[i])
}
}
}) })
} }
} }

32
plugins/chatlog.js Executable file
View file

@ -0,0 +1,32 @@
const chatlog = require('../util/chatlog.js')
const fs = require('fs')
const settings = require('../settings.json')
const checkLog = () => {
if (settings.disableLogging) return
try {
if (!fs.readdirSync('.').includes('logs')) fs.mkdirSync('logs')
const dateToday = new Date(Date.now())
const dateTomorrow = new Date(Date.now() + 86400000)
const filenameToday = `${dateToday.getUTCMonth() + 1}-${dateToday.getUTCDate()}-${dateToday.getUTCFullYear()}`
const filenameTomorrow = `${dateTomorrow.getUTCMonth() + 1}-${dateTomorrow.getUTCDate()}-${dateTomorrow.getUTCFullYear()}`
if (!fs.readdirSync('./logs').includes(filenameToday)) fs.mkdirSync(`logs/${filenameToday}`)
if (!fs.readdirSync('./logs').includes(filenameTomorrow)) fs.mkdirSync(`logs/${filenameTomorrow}`) // Create tomorrow's log directory early
} catch (e) {
console.log(e) // Prevents some crashes when disk space is full or when the permissions are incorrect
}
}
setInterval(checkLog, 3600000) // Runs once every hour,
checkLog() // and at bot startup.
module.exports = {
load: (b) => {
b.on('plainchat', (msg, type) => {
if (!settings.disableLogging && !settings.disableChatLogging) chatlog(`chat_${b.host.host}_${b.host.port}`, `[${type}] ${msg}`)
})
b.on('command', (name, uuid, text) => {
if (!settings.disableLogging && !settings.disableCommandLogging) chatlog(`cmd_${b.host.host}_${b.host.port}`, `${name} (${uuid}): ${text}`)
})
}
}

View file

@ -14,8 +14,8 @@ module.exports = {
b.cloops.splice(index, 1) b.cloops.splice(index, 1)
} }
b.clearCloops = function () { b.clearCloops = function () {
for (const i in b.cloops) { for (const cloop of b.cloops) {
clearInterval(b.cloops[i].interval) clearInterval(cloop.interval)
} }
b.cloops = [] b.cloops = []
} }

View file

@ -3,13 +3,38 @@ const hashcheck = require('../util/hashcheck.js')
const settings = require('../settings.json') const settings = require('../settings.json')
const { getMessage } = require('../util/lang.js') const { getMessage } = require('../util/lang.js')
const cmds = require('../util/commands.js') const cmds = require('../util/commands.js')
const fs = require('fs')
if (!fs.readdirSync('.').includes('userPref') && !settings.userSettingsDisabled) fs.mkdirSync('userPref')
const loadSettings = function (uuid) {
try {
if (settings.userSettingsDisabled) {
return {}
} else {
return require(`../userPref/${uuid}.json`)
}
} catch (e) {
return {}
}
}
module.exports = { module.exports = {
load: (b) => { load: (b) => {
b.prefix = settings.prefix b.prefix = settings.prefix
b.lastCmd = 0 b.lastCmd = 0
b.runCommand = (name, uuid, text, prefix) => { b.on('chat', (data) => {
const fullCommand = data.message
for (const prefix of b.prefix) {
if (fullCommand.startsWith(prefix)) {
const command = fullCommand.slice(prefix.length)
b.runCommand(data.username, data.nickname, data.uuid, command, data.type, prefix)
}
}
})
b.runCommand = (name, nickname, uuid, text, msgType, prefix) => {
if (uuid === '00000000-0000-0000-0000-000000000000') return if (uuid === '00000000-0000-0000-0000-000000000000') return
if (Date.now() - b.lastCmd <= 1000) return if (Date.now() - b.lastCmd <= 1000) return
const userSettings = loadSettings(uuid)
b.lastCmd = Date.now() b.lastCmd = Date.now()
const cmd = text.split(' ') const cmd = text.split(' ')
const lang = settings.defaultLang const lang = settings.defaultLang
@ -17,6 +42,7 @@ module.exports = {
if (verify > 0) { if (verify > 0) {
text = cmd.slice(0, cmd.length - 1).join(' ') text = cmd.slice(0, cmd.length - 1).join(' ')
} }
b.emit('command', name, uuid, text, prefix)
if (cmds[cmd[0].toLowerCase()]) { if (cmds[cmd[0].toLowerCase()]) {
const command = cmds[cmd[0].toLowerCase()] const command = cmds[cmd[0].toLowerCase()]
if (command.level !== undefined && command.level > verify) { if (command.level !== undefined && command.level > verify) {
@ -32,7 +58,7 @@ module.exports = {
return return
} }
try { try {
cmds[cmd[0].toLowerCase()].execute(new Command(uuid, name, 'nick N/A', text, prefix, b, verify)) cmds[cmd[0].toLowerCase()].execute(new Command(uuid, name, nickname, text, msgType, prefix, b, verify, userSettings))
} catch (e) { } catch (e) {
console.log(e) console.log(e)
b.tellraw(uuid, { b.tellraw(uuid, {

View file

@ -19,7 +19,7 @@ module.exports = {
b.advanceccq = function () { b.advanceccq = function () {
if (b.ccq[0] && b.ccq[0].length !== 0) { if (b.ccq[0] && b.ccq[0].length !== 0) {
b._client.write('update_command_block', { b._client.write('update_command_block', {
command: b.ccq[0], command: '/',
location: { location: {
x: b.commandPos.x + b.blocknoX, x: b.commandPos.x + b.blocknoX,
y: b.commandPos.y + b.blocknoY, y: b.commandPos.y + b.blocknoY,
@ -29,7 +29,7 @@ module.exports = {
flags: 1 flags: 1
}) })
b._client.write('update_command_block', { b._client.write('update_command_block', {
command: b.ccq[0], command: b.ccq[0].substr(0, 32767),
location: { location: {
x: b.commandPos.x + b.blocknoX, x: b.commandPos.x + b.blocknoX,
y: b.commandPos.y + b.blocknoY, y: b.commandPos.y + b.blocknoY,
@ -55,6 +55,14 @@ module.exports = {
} }
b._client.on('login', () => { b._client.on('login', () => {
b._client.write('settings', {
locale: 'ru_RU',
viewDistance: 4,
chatFlags: 0, // Enable full chat functionality
chatColors: true,
skinParts: 127, // Allow the second layer of the skin, when the bot is sudoed to do /skin
mainHand: 1 // Right hand
})
b.add_sc_task('cc', () => { b.add_sc_task('cc', () => {
b.chat(b.refillCoreCmd) b.chat(b.refillCoreCmd)
}, true) }, true)
@ -63,7 +71,7 @@ module.exports = {
}) })
}) })
b.on('ccstart', () => { b.on('ccstart', () => {
setTimeout(() => { b.interval.ccqi = setInterval(b.advanceccq, 3) }, 1000) // 1 Second and 3 Milliseconds setTimeout(() => { b.interval.ccqi = setInterval(b.advanceccq, 2) }, 1000)
b.ccStarted = true b.ccStarted = true
}) })
b.on('chat', (data) => { b.on('chat', (data) => {

View file

@ -1,29 +1,29 @@
const parse = require('../util/chatparse_plain') const parse = require('../util/chatparse_plain')
const parseNBT = require('../util/chatparse_1204') const parseNBT = require('../util/parseNBT')
module.exports = { module.exports = {
load: (b) => { load: (b) => {
b.players = {} b.players = {}
b._client.on('player_info', (data) => { b._client.on('player_info', (data) => {
const buffer2 = {} const buffer2 = {}
for (const i in data.data) { for (const player of data.data) {
let uuid let uuid
if (data.data[i].uuid) { if (player.uuid) {
uuid = data.data[i].uuid uuid = player.uuid
} else if (data.data[i].UUID) { } else if (player.UUID) {
uuid = data.data[i].UUID uuid = player.UUID
} }
let displayName let displayName
if (data.data[i].displayName !== undefined) { if (player.displayName !== undefined) {
displayName = data.data[i].displayName displayName = player.displayName
} else { } else {
displayName = '{"text":"[[[[ No display name ]]]]"}' displayName = '{"text":"[[[[ No display name ]]]]"}'
} }
if (data.data[i].player && data.data[i].player.name !== undefined) { if (player.player && player.player.name !== undefined) {
buffer2[uuid] = { realName: data.data[i].player.name, displayName: parse(parseNBT(displayName)) } buffer2[uuid] = { realName: player.player.name, displayName: parse(parseNBT(displayName)) }
} else if (data.data[i].name !== undefined) { } else if (player.name !== undefined) {
buffer2[uuid] = { realName: data.data[i].name, displayName: parse(parseNBT(displayName)) } buffer2[uuid] = { realName: player.name, displayName: parse(parseNBT(displayName)) }
} else if (data.data[i].displayName !== undefined) { } else if (player.displayName !== undefined) {
buffer2[uuid] = { displayName: displayName.plain } buffer2[uuid] = { displayName: parse(parseNBT(displayName)) }
} }
} }
for (const uuid in buffer2) { for (const uuid in buffer2) {
@ -48,5 +48,20 @@ module.exports = {
} }
return '[[[[ no name ]]]]' return '[[[[ no name ]]]]'
} }
b.findRealNameFromUUID = (name) => {
if (b.players[name]) {
return b.players[name].realName
} else {
return '[[[[ no name ]]]]'
}
}
b.findDisplayName = (name) => {
if (b.players[name]) {
const displayName = b.players[name].displayName.split(' ')
return displayName[displayName.length - 1]
} else {
return '[[[[ No display name ]]]]'
}
}
} }
} }

View file

@ -11,13 +11,18 @@ class SCTask {
module.exports = { module.exports = {
load: (b) => { load: (b) => {
b.sc_tasks = {} b.sc_tasks = {}
b.selfcareRun = 0
b.interval.sc = setInterval(() => { b.interval.sc = setInterval(() => {
if (Date.now() - b.selfcareRun <= 600) {
return
}
for (const i in b.sc_tasks) { for (const i in b.sc_tasks) {
if (b.sc_tasks[i].failed) { if (b.sc_tasks[i].failed) {
b.sc_tasks[i].failTask() b.sc_tasks[i].failTask()
} }
} }
}, 1000) b.selfcareRun = Date.now()
}, 40)
b.add_sc_task = (name, failTask, startFailed) => { b.add_sc_task = (name, failTask, startFailed) => {
b.sc_tasks[name] = new SCTask(failTask, startFailed) b.sc_tasks[name] = new SCTask(failTask, startFailed)
} }
@ -53,7 +58,7 @@ module.exports = {
}) })
} }
// Gamemode // Gamemode / end portal bug
b.add_sc_task('gamemode', () => { b.add_sc_task('gamemode', () => {
b.chat('/minecraft:gamemode creative') b.chat('/minecraft:gamemode creative')
}) })
@ -62,6 +67,8 @@ module.exports = {
b.sc_tasks.gamemode.failed = 1 b.sc_tasks.gamemode.failed = 1
} else if (p.reason === 3 && p.gameMode === 1) { } else if (p.reason === 3 && p.gameMode === 1) {
b.sc_tasks.gamemode.failed = 0 b.sc_tasks.gamemode.failed = 0
} else if (p.reason === 4) {
b.sc_tasks.respawn.failed = 1
} }
}) })
@ -71,7 +78,8 @@ module.exports = {
b.sc_tasks.respawn.failed = 0 b.sc_tasks.respawn.failed = 0
}) })
b.on('chat', (data) => { b.on('chat', (data) => {
if (data.json.translate === 'chat.disabled.options' || (data.json.extra && data.json.extra[0] && data.json.extra[0].translate === 'chat.disabled.options')) { if (data.json.translate === 'chat.disabled.options' || (data.json.extra && data.json.extra[0] && data.json.extra[0].translate === 'chat.disabled.options') ||
data.json.translate === 'Chat disabled in client options' || (data.json.extra && data.json.extra[0] && data.json.extra[0].translate === 'Chat disabled in client options')) {
b.sc_tasks.respawn.failed = 1 b.sc_tasks.respawn.failed = 1
} }
}) })

View file

@ -1,6 +1,4 @@
{ {
"secret":"/path/to/secrets/file/secret.json",
"name": "Minecraft Bot",
"version_mc": "1.20.4", "version_mc": "1.20.4",
"defaultLang": "en-US", "defaultLang": "en-US",
"terminalMode": "blackTerminal_24bit", "terminalMode": "blackTerminal_24bit",

View file

@ -1,23 +1,41 @@
// HOW TO WRITE CLASS JS
const settings = require('../settings.json') const settings = require('../settings.json')
class Command { class Command {
constructor (uuid, user, nick, cmd, prefix, bot, verify, lang = settings.defaultLang) { constructor (uuid, user, nick, cmd, msgType, prefix, bot, verify, prefs) {
this.send = (text, uuid) => { bot.tellraw(uuid || '@a', text) } this.send = (text, uuid) => { bot.tellraw(uuid || '@a', text) }
this.reply = text => bot.tellraw(uuid, text) this.reply = text => bot.tellraw(uuid, text)
this.uuid = uuid this.uuid = uuid
this.username = user this.username = user
this.nickname = nick this.nickname = nick
this.command = cmd this.command = cmd
this.msgType = msgType
this.prefix = prefix this.prefix = prefix
this.bot = bot this.bot = bot
this.type = 'minecraft' this.type = 'minecraft'
this.index = bot.id
this.args = cmd.split(' ').slice(1) this.args = cmd.split(' ').slice(1)
this.cmdName = cmd.split(' ')[0]
this.verify = verify this.verify = verify
this.host = bot.host.host this.host = bot.host.host
this.port = bot.host.port this.port = bot.host.port
this.lang = lang this.serverName = bot.host.options.name
this.colors = settings.colors this.prefs = prefs
if (prefs.lang) {
this.lang = prefs.lang
} else {
this.lang = settings.defaultLang
}
const _colors = {}
if (prefs.colorPrimary) {
_colors.primary = prefs.colorPrimary
} else {
_colors.primary = settings.colors.primary
}
if (prefs.colorSecondary) {
_colors.secondary = prefs.colorSecondary
} else {
_colors.secondary = settings.colors.secondary
}
this.colors = _colors
} }
} }

View file

@ -1,25 +1,26 @@
// HOW TO WRITE CLASS JS
const index = require('../index.js') const index = require('../index.js')
const parse = require('../util/chatparse_console.js') const parse = require('../util/chatparse_console.js')
const settings = require('../settings.json') const settings = require('../settings.json')
class ConsoleCommand { class ConsoleCommand {
constructor (cmd, index2) { constructor (cmd, index2) {
this.send = () => {} // not needed for console this.send = () => {}
this.reply = text => process.stdout.write(parse(text) + '\n') this.reply = text => process.stdout.write(parse(text) + '\n')
this.uuid = 'dde5a2a6-ebdd-7bbb-8eac-f75b10c10446' // hard-coded because uuid does not exist at console this.uuid = 'dde5a2a6-ebdd-7bbb-8eac-f75b10c10446'
this.username = 'Owner' this.username = 'Owner'
this.nickname = 'Console' this.nickname = 'Owner'
this.command = cmd this.command = cmd
this.prefix = '' // prefix does not exist at console this.msgType = '_bot_console'
this.prefix = ''
this.bot = index2 >= 0 this.bot = index2 >= 0
? index.bot[index2] ? index.bot[index2]
: {} : {}
this.type = 'console' this.type = 'console'
this.index = index2
this.args = cmd.split(' ').slice(1) this.args = cmd.split(' ').slice(1)
this.cmdName = cmd.split(' ')[0]
this.verify = 3 this.verify = 3
this.host = '' this.host = ''
this.port = '3' // :3 this.port = '3'
this.serverName = 'botvX Console'
this.lang = settings.defaultLang this.lang = settings.defaultLang
this.colors = settings.colors this.colors = settings.colors
} }

17
util/chatlog.js Normal file
View file

@ -0,0 +1,17 @@
const fs = require('fs')
const settings = require('../settings.json')
module.exports = function (fileName, item) {
if (settings.disableLogging) return
const dateToday = new Date(Date.now())
const UTCYears = dateToday.getUTCFullYear()
const UTCMonths = dateToday.getUTCMonth() + 1
const UTCDays = dateToday.getUTCDate()
const UTCHours = dateToday.getUTCHours()
const UTCMinutes = dateToday.getUTCMinutes().toString().padStart(2, '0')
const UTCSeconds = dateToday.getUTCSeconds().toString().padStart(2, '0')
const UTCMilliSeconds = dateToday.getUTCMilliseconds().toString().padStart(3, '0')
const filenameToday = `${UTCMonths}-${UTCDays}-${UTCYears}`
const logDate = `${UTCMonths}/${UTCDays}/${UTCYears} ${UTCHours}:${UTCMinutes}:${UTCSeconds}.${UTCMilliSeconds}`
fs.appendFileSync(`logs/${filenameToday}/${fileName}.txt`, `[${logDate}] ${item}\n`)
}

View file

@ -11,21 +11,45 @@ if (_consoleColors[settings.terminalMode]) {
consoleColors = _consoleColors.none.fourBit consoleColors = _consoleColors.none.fourBit
consoleColors24 = _consoleColors.none.twentyFourBit consoleColors24 = _consoleColors.none.twentyFourBit
} }
const process8bitColorChannel = (value) => {
if (value < 65) return 0
if (value < 115) return 1
if (value < 155) return 2
if (value < 195) return 3
if (value < 235) return 4
return 5
}
const hexColorParser = (color) => { const hexColorParser = (color) => {
if (!consoleColors24.enabled || consoleColors24.bit !== 24) { // Hex color parsing to the 8 bit and 4 bit modes has not been implemented yet if (!consoleColors24.enabled || consoleColors24.bit === 4) { // Hex color parsing to the 4 bit mode has not been implemented yet
return '' return ''
} }
let out = '\x1B[0;' if (consoleColors24.bit === 24) {
const redChannel = Number(`0x${color.slice(1, 3)}`) let out = '\x1B[0;'
const greenChannel = Number(`0x${color.slice(3, 5)}`) const redChannel = Number(`0x${color.slice(1, 3)}`)
const blueChannel = Number(`0x${color.slice(5, 7)}`) const greenChannel = Number(`0x${color.slice(3, 5)}`)
if (!consoleColors24.lightMode && redChannel < 64 && greenChannel < 64 && blueChannel < 64) { const blueChannel = Number(`0x${color.slice(5, 7)}`)
out += '48;2;220;220;220;' if (!consoleColors24.lightMode && redChannel < 64 && greenChannel < 64 && blueChannel < 64) {
} else if (consoleColors24.lightMode && ((redChannel > 192 && greenChannel > 192 && blueChannel > 192) || greenChannel > 160)) { out += '48;2;220;220;220;'
out += '48;2;0;0;0;' } else if (consoleColors24.lightMode && ((redChannel > 192 && greenChannel > 192 && blueChannel > 192) || greenChannel > 160)) {
out += '48;2;0;0;0;'
}
return out + `38;2;${redChannel};${greenChannel};${blueChannel}m`
} else if (consoleColors24.bit === 8) {
let out = '\x1B[0;'
const redChannel = Number(`0x${color.slice(1, 3)}`)
const greenChannel = Number(`0x${color.slice(3, 5)}`)
const blueChannel = Number(`0x${color.slice(5, 7)}`)
if (!consoleColors24.lightMode && redChannel < 65 && greenChannel < 65 && blueChannel < 65) {
out += '48;5;253;'
} else if (consoleColors24.lightMode && ((redChannel > 194 && greenChannel > 194 && blueChannel > 194) || greenChannel > 154)) {
out += '48;5;16;'
}
const redOut = process8bitColorChannel(redChannel)
const greenOut = process8bitColorChannel(greenChannel)
const blueOut = process8bitColorChannel(blueChannel)
const colorValue = 16 + 36 * redOut + 6 * greenOut + blueOut
return out + `38;5;${colorValue}m`
} }
return out + `38;2;${redChannel};${greenChannel};${blueChannel}m`
} }
const processColor = (col, rcol) => { const processColor = (col, rcol) => {
@ -41,8 +65,8 @@ const processColor = (col, rcol) => {
} }
const parse = function (_data, l = 0, resetColor = consoleColors.reset) { const parse = function (_data, l = 0, resetColor = consoleColors.reset) {
if (l >= 12) { if (l >= 4) {
return ['', '', ''] return ''
} }
let data let data
if (typeof _data === 'string') { if (typeof _data === 'string') {
@ -70,23 +94,25 @@ const parse = function (_data, l = 0, resetColor = consoleColors.reset) {
if (typeof _text === 'number') { if (typeof _text === 'number') {
_text = _text.toString() _text = _text.toString()
} }
out += _text.replaceAll('\x1b', '').replaceAll('\x0e', '') // Remove escape codes and [SO] from console format out += _text.replaceAll('\x1b', '').replaceAll('\x0e', '')
} }
if (data.translate) { if (data.translate) {
let trans = data.translate.replace(/%%/g, '\ue123').replaceAll('\x1b', '').replaceAll('\x0e', '') // Remove escape codes from console format let trans = data.translate.replaceAll('%%', '\ud900\ud801').replaceAll('\x1b', '').replaceAll('\x0e', '')
if (lang[trans] !== undefined) { if (lang[trans] !== undefined) {
trans = lang[trans].replace(/%%/g, '\ue123') trans = lang[trans].replace(/%%/g, '\ue123')
} }
for (const i in data.with) { if (data.with) {
const j2 = parse(data.with[i], l + 1, data.color ? processColor(data.color, resetColor) : resetColor) data.with.forEach((item, i) => {
trans = trans.replace(/%s/, j2.replace(/%s/g, '\ue124').replace(/\$s/g, '\ue125')) const j2 = parse(item, l + 1, data.color ? processColor(data.color, resetColor) : resetColor)
trans = trans.replaceAll(`%${+i + 1}$s`, j2.replace(/%s/g, '\ue124').replace(/\$s/g, '\ue125')) trans = trans.replace(/%s/, j2.replaceAll('%s', '\ud900\ud804').replaceAll('$s', '\ud900\ud805'))
trans = trans.replaceAll(`%${+i + 1}$s`, j2.replaceAll('%s', '\ud900\ud804').replaceAll('$s', '\ud900\ud805'))
})
} }
out += trans.replace(/\ue123/g, '%').replace(/\ue124/g, '%s').replace(/\ue125/g, '$s') out += trans.replaceAll('\ud900\ud801', '%').replaceAll('\ud900\ud804', '%s').replaceAll('\ud900\ud805', '$s')
} }
if (data.extra) { if (data.extra) {
for (const i in data.extra) { for (const item of data.extra) {
const parsed = parse(data.extra[i], l, data.color ? processColor(data.color, resetColor) : resetColor) const parsed = parse(item, l, data.color ? processColor(data.color, resetColor) : resetColor)
out += parsed out += parsed
} }
} }

96
util/chatparse_mc.js Normal file
View file

@ -0,0 +1,96 @@
const lang = require('./mc_lang.js')
const consoleColors = {
dark_red: '§4',
red: '§c',
dark_green: '§2',
green: '§a',
gold: '§6',
yellow: '§e',
dark_blue: '§1',
blue: '§9',
dark_purple: '§5',
light_purple: '§d',
dark_aqua: '§3',
aqua: '§b',
black: '§0',
gray: '§7',
dark_gray: '§8',
white: '§f',
reset: '§r§f'
}
const processColor = (col, rcol) => {
let out
if (col === 'reset') {
out = rcol
} else {
out = consoleColors[col]
}
return out
}
const parse = function (_data, l = 0, resetColor = consoleColors.reset) {
if (l >= 4) {
return ''
}
let data
if (typeof _data === 'string') {
data = { text: _data, color: 'reset' }
} else if (typeof _data === 'number') {
data = { text: _data + '', color: 'reset' }
} else if (_data.constructor === Array) {
data = { extra: _data, color: 'reset' }
} else {
data = _data
}
if (data['']) {
data.text = data['']
if (!data.color) data.color = 'reset'
}
let out = ''
if (data.color) {
out += processColor(data.color, resetColor)
} else {
out += resetColor
}
if (data.text) {
let _text = data.text
if (typeof _text === 'number') {
_text = _text.toString()
}
out += _text.replaceAll('\x1b', '').replaceAll('\x0e', '')
}
if (data.translate) {
let trans = data.translate.replaceAll('%%', '\ud900\ud801').replaceAll('\x1b', '').replaceAll('\x0e', '')
if (lang[trans] !== undefined) {
trans = lang[trans].replace(/%%/g, '\ue123')
}
if (data.with) {
data.with.forEach((item, i) => {
const j2 = parse(item, l + 1, data.color ? processColor(data.color, resetColor) : resetColor)
trans = trans.replace(/%s/, j2.replaceAll('%s', '\ud900\ud804').replaceAll('$s', '\ud900\ud805'))
trans = trans.replaceAll(`%${+i + 1}$s`, j2.replaceAll('%s', '\ud900\ud804').replaceAll('$s', '\ud900\ud805'))
})
}
out += trans.replaceAll('\ud900\ud801', '%').replaceAll('\ud900\ud804', '%s').replaceAll('\ud900\ud805', '$s')
}
if (data.extra) {
for (const item of data.extra) {
const parsed = parse(item, l, data.color ? processColor(data.color, resetColor) : resetColor)
out += parsed
}
}
out += resetColor
return out
}
const parse2 = function (_data, l, resetColor) {
try {
return parse(_data)
} catch (e) {
console.error(e)
return `\x1B[0m\x1B[38;2;255;85;85mAn error occured while parsing a message. See console for more information.\nJSON that caused the error: ${JSON.stringify(_data)}`
}
}
module.exports = parse2

View file

@ -1,7 +1,7 @@
const lang = require('./mc_lang.js') const lang = require('./mc_lang.js')
const parse = function (_data, l = 0) { const parse = function (_data, l = 0) {
if (l >= 12) { if (l >= 4) {
return ['', '', ''] return ''
} }
let data let data
if (typeof _data === 'string') { if (typeof _data === 'string') {
@ -31,14 +31,14 @@ const parse = function (_data, l = 0) {
} }
for (const i in data.with) { for (const i in data.with) {
const j2 = parse(data.with[i], l + 1) const j2 = parse(data.with[i], l + 1)
trans = trans.replace(/%s/, j2.replace(/%s/g, '\ue124').replace(/\$s/g, '\ue125')) trans = trans.replace(/%s/, j2.replaceAll('%s', '\ud900\ud804').replaceAll('$s', '\ud900\ud805'))
trans = trans.replaceAll(`%${+i + 1}$s`, j2.replace(/%s/g, '\ue124').replace(/\$s/g, '\ue125')) trans = trans.replaceAll(`%${+i + 1}$s`, j2.replaceAll('%s', '\ud900\ud804').replaceAll('$s', '\ud900\ud805'))
} }
out += trans.replace(/\ue123/g, '%').replace(/\ue124/g, '%s').replace(/\ue125/g, '$s') out += trans.replaceAll('\ud900\ud801', '%').replaceAll('\ud900\ud804', '%s').replaceAll('\ud900\ud805', '$s')
} }
if (data.extra) { if (data.extra) {
for (const i in data.extra) { for (const item of data.extra) {
const parsed = parse(data.extra[i], l) const parsed = parse(item, l)
out += parsed out += parsed
} }
} }

View file

@ -1,19 +1,19 @@
const fs = require('fs') const fs = require('fs')
const cmds = Object.create(null) const cmds = Object.create(null)
const bpl = fs.readdirSync('./commands') const bpl = fs.readdirSync('./commands')
for (const i in bpl) { for (const plugin of bpl) {
if (!bpl[i].endsWith('.js')) { if (!plugin.endsWith('.js')) {
continue continue
} }
try { try {
const commandName = bpl[i].split('.js')[0] const commandName = plugin.split('.js')[0]
cmds[commandName] = require(`../commands/${bpl[i]}`) cmds[commandName] = require(`../commands/${plugin}`)
if (cmds[commandName].level === undefined) { if (cmds[commandName].level === undefined) {
cmds[commandName].level = 0 cmds[commandName].level = 0
} }
if (cmds[commandName].aliases) { if (cmds[commandName].aliases) {
for (const j in cmds[commandName].aliases) { for (const alias of cmds[commandName].aliases) {
cmds[cmds[commandName].aliases[j]] = { cmds[alias] = {
execute: cmds[commandName].execute, execute: cmds[commandName].execute,
alias: commandName, alias: commandName,
usage: cmds[commandName].usage, usage: cmds[commandName].usage,

View file

@ -53,23 +53,23 @@
}, },
"blackTerminal_8bit":{ "blackTerminal_8bit":{
"fourBit":{ "fourBit":{
"dark_red": "\u001B[0;38;5;1m", "dark_red": "\u001B[0;38;5;124m",
"red": "\u001B[0;38;5;9m", "red": "\u001B[0;38;5;203m",
"dark_green": "\u001B[0;38;5;2m", "dark_green": "\u001B[0;38;5;34m",
"green": "\u001B[0;38;5;10m", "green": "\u001B[0;38;5;83m",
"gold": "\u001B[0;38;5;3m", "gold": "\u001B[0;38;5;214m",
"yellow": "\u001B[0;38;5;11m", "yellow": "\u001B[0;38;5;227m",
"dark_blue": "\u001B[0;38;5;4m", "dark_blue": "\u001B[0;38;5;19m",
"blue": "\u001B[0;38;5;12m", "blue": "\u001B[0;38;5;63m",
"dark_purple": "\u001B[0;38;5;5m", "dark_purple": "\u001B[0;38;5;127m",
"light_purple": "\u001B[0;38;5;13m", "light_purple": "\u001B[0;38;5;207m",
"dark_aqua": "\u001B[0;38;5;6m", "dark_aqua": "\u001B[0;38;5;37m",
"aqua": "\u001B[0;38;5;14m", "aqua": "\u001B[0;38;5;87m",
"black": "\u001B[0;48;5;15;38;5;0m", "black": "\u001B[0;48;5;253;38;5;16m",
"gray": "\u001B[0;38;5;7m", "gray": "\u001B[0;38;5;145m",
"dark_gray": "\u001B[0;38;5;8m", "dark_gray": "\u001B[0;38;5;59m",
"white": "\u001B[0;38;5;15m", "white": "\u001B[0;38;5;231m",
"reset": "\u001B[0;38;5;15m" "reset": "\u001B[0;38;5;231m"
}, },
"twentyFourBit":{ "twentyFourBit":{
"enabled": true, "enabled": true,
@ -79,23 +79,23 @@
}, },
"whiteTerminal_8bit":{ "whiteTerminal_8bit":{
"fourBit":{ "fourBit":{
"dark_red": "\u001B[0;38;5;1m", "dark_red": "\u001B[0;38;5;124m",
"red": "\u001B[0;38;5;9m", "red": "\u001B[0;38;5;203m",
"dark_green": "\u001B[0;38;5;2m", "dark_green": "\u001B[0;38;5;34m",
"green": "\u001B[0;48;5;0;38;5;10m", "green": "\u001B[0;48;5;16;38;5;83m",
"gold": "\u001B[0;38;5;3m", "gold": "\u001B[0;38;5;214m",
"yellow": "\u001B[0;48;5;0;38;5;11m", "yellow": "\u001B[0;48;5;16;38;5;227m",
"dark_blue": "\u001B[0;38;5;4m", "dark_blue": "\u001B[0;38;5;19m",
"blue": "\u001B[0;38;5;12m", "blue": "\u001B[0;38;5;63m",
"dark_purple": "\u001B[0;38;5;5m", "dark_purple": "\u001B[0;38;5;127m",
"light_purple": "\u001B[0;38;5;13m", "light_purple": "\u001B[0;38;5;207m",
"dark_aqua": "\u001B[0;38;5;6m", "dark_aqua": "\u001B[0;38;5;37m",
"aqua": "\u001B[0;48;5;0;38;5;14m", "aqua": "\u001B[0;48;5;16;38;5;87m",
"black": "\u001B[0;38;5;0m", "black": "\u001B[0;38;5;16m",
"gray": "\u001B[0;38;5;7m", "gray": "\u001B[0;38;5;145m",
"dark_gray": "\u001B[0;38;5;8m", "dark_gray": "\u001B[0;38;5;59m",
"white": "\u001B[0;48;5;0;38;5;15m", "white": "\u001B[0;48;5;16;38;5;231m",
"reset": "\u001B[0;48;5;0;38;5;15m" "reset": "\u001B[0;48;5;16;38;5;231m"
}, },
"twentyFourBit":{ "twentyFourBit":{
"enabled": true, "enabled": true,

View file

@ -1,6 +1,5 @@
const crypto = require('crypto') const crypto = require('crypto')
const settings = require('../settings.json') const secret = require('../secret.json')
const secret = require(settings.secret)
module.exports = function (cmd) { module.exports = function (cmd) {
const cmdWithoutHash = cmd.slice(0, cmd.length - 1).join(' ') const cmdWithoutHash = cmd.slice(0, cmd.length - 1).join(' ')
const _dateString = Date.now().toString() const _dateString = Date.now().toString()

View file

@ -2,13 +2,13 @@ const fs = require('fs')
const languages = {} const languages = {}
const loadplug = (botno) => { const loadplug = (botno) => {
const bpl = fs.readdirSync('util/lang') const bpl = fs.readdirSync('lang')
for (const i in bpl) { for (const plugin of bpl) {
if (!bpl[i].endsWith('.json')) { if (!plugin.endsWith('.json')) {
continue continue
} }
try { try {
languages[bpl[i].split('.')[0]] = require(`./lang/${bpl[i]}`) languages[plugin.split('.')[0]] = require(`../lang/${plugin}`)
} catch (e) { console.log(e) } } catch (e) { console.log(e) }
} }
} }
@ -18,17 +18,20 @@ const getMessage = function (l, msg, with2) {
let message = msg.replace(/%%/g, '\ue123') let message = msg.replace(/%%/g, '\ue123')
if (languages[l] && languages[l][message] !== undefined) { if (languages[l] && languages[l][message] !== undefined) {
message = languages[l][message].replace(/%%/g, '\ue123') message = languages[l][message].replace(/%%/g, '\ue123')
} else if (languages[l] && languages['en-US'][message] !== undefined) { } else if (languages['en-US'] && languages['en-US'][message] !== undefined) {
message = languages['en-US'][message].replace(/%%/g, '\ue123') message = languages['en-US'][message].replace(/%%/g, '\ue123')
} }
for (const i in with2) { if (with2) {
message = message.replace(/%s/, with2[i].replace(/%s/g, '\ue124').replace(/\$s/g, '\ue125')) with2.forEach((withItem, i) => {
message = message.replaceAll(`%${+i + 1}$s`, with2[i].replace(/%s/g, '\ue124').replace(/\$s/g, '\ue125')) message = message.replace(/%s/, withItem.replace(/%s/g, '\ue124').replace(/\$s/g, '\ue125'))
message = message.replaceAll(`%${+i + 1}$s`, withItem.replace(/%s/g, '\ue124').replace(/\$s/g, '\ue125'))
})
} }
return message.replace(/\ue123/g, '%').replace(/\ue124/g, '%s').replace(/\ue125/g, '$s') return message.replace(/\ue123/g, '%').replace(/\ue124/g, '%s').replace(/\ue125/g, '$s')
} }
module.exports = { module.exports = {
languages: Object.keys(languages),
getMessage, getMessage,
formatTime: function (time, language) { formatTime: function (time, language) {
let finalString = '' let finalString = ''

View file

@ -1,70 +0,0 @@
{
"time.week": " week ",
"time.weekPlural": " weeks ",
"time.day": " day ",
"time.dayPlural": " days ",
"time.hour": " houw ",
"time.hourPlural": " houws ",
"time.minute": " minyute ",
"time.minutePlural": " minyutes ",
"time.second": " second ",
"time.secondPlural": " seconds ",
"command.about.usage": "",
"command.about.desc": "About the bot",
"command.cb.usage": " <command>",
"command.cb.desc": "Wun a command in a command bwock",
"command.cloop.usage": " add <wate> <command>|| remove <index>|| list|| clear",
"command.cloop.desc": "Manage command woops",
"command.eval.usage": " <code>",
"command.eval.desc": "Wun JavaScwipt code",
"command.help.usage": " [cmd]",
"command.help.desc": "Shows command hewp",
"command.logoff.usage": "",
"command.logoff.desc": "Disconnyect and weconnyect the bot fwom a sewvew",
"command.netmsg.usage": " <message>",
"command.netmsg.desc": "Send a message to aww sewvews the bot is connyected to",
"command.refill.usage": "",
"command.refill.desc": "Wefiww cowe",
"command.say.usage": " <message>",
"command.say.desc": "Sends a message to chat",
"command.serverinfo.usage": "",
"command.serverinfo.desc": "Get system/bot info",
"command.stop.usage": "",
"command.stop.desc": "Westawt bot",
"command.template.usage": " <wequiwed> [optionyaw]",
"command.template.desc": "Does nyothing",
"command.tpr.desc": "Tewepowt to a wandom wocation",
"command.tpr.usage": "",
"command.verify.usage": " [awgs...]",
"command.verify.desc": "Check the hashing system",
"command.about.author": "%s - a Minyecwaft bot made by %s",
"command.about.version": "Vewsion %s",
"command.about.preRelease": "This is pwewewease softwawe - thewe may be ewwows, and featuwes may be changed ow wemoved at any time.",
"command.about.sourceCode": "Souwce code: %s",
"command.about.sourceCode.openInBrowser": "Cwick to open the souwce code wink in youw defauwt bwowsew",
"command.about.serverinfo": "To view system infowmation, wun the command %s.",
"command.cloop.error.tooShort": "Command woops must have a wate above 20ms.",
"command.cloop.error.subcommand": "Unknyown subcommand, pwease do %s",
"command.cloop.success.add": "Added command woop with command %s and wate %s",
"command.cloop.success.remove": "Wemoved command woop %s",
"command.cloop.success.clear": "Cweawed aww command woops",
"command.cloop.list": "%s: Command: %s Wate: %s",
"command.help.cmdList": "Commands:",
"command.help.commandInfo": "%s%s - %s",
"command.help.commandUsage": "Usage - %s%s",
"command.help.commandDesc": "Descwiption - %s",
"command.help.commandPerms": "Wequiwed pewmissions - %s",
"command.help.permsNormal": "Nyowmaw",
"command.help.permsTrusted": "Twusted",
"command.help.permsOwner": "Ownyew",
"command.help.permsConsole": "Consowe",
"command.help.noCommand": "Command does nyot exist",
"command.help.alias": "Awias to %s",
"command.tpr.success": "Tewepowting %s to %s, %s, %s",
"command.verify.success": "Successfuwwy vewified with pewmission wevew %s",
"command.error": "An ewwow occuwed (check consowe fow mowe info)",
"command.disallowed.perms": "You do nyot have pewmission to wun this command. If you do have pewmission, pwease make suwe you put the command hash at the end, ow wan the command thwough youw cwient's hashing system.",
"command.disallowed.perms.yourLevel": "Youw pewmission wevew: %s",
"command.disallowed.perms.cmdLevel": "Command wequiwes: %s",
"copyText": "Cwick to copy!"
}

View file

@ -1,3 +1,4 @@
const crypto = require('crypto')
const rsg = function (count) { const rsg = function (count) {
let output = '' let output = ''
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
@ -29,9 +30,19 @@ const rsg = function (count) {
} }
return output return output
} }
const rsgLegal = function (count) {
let output = ''
if (Math.random() > 0.5) {
output += 'uwu_'
} else {
output += 'owo_'
}
output += crypto.randomBytes(count).toString('hex')
return output
}
module.exports = function (legal) { module.exports = function (legal) {
if (legal) { if (legal) {
return Math.floor(Math.random() * 1000000).toString() return rsgLegal(6)
} else { } else {
return rsg(6 + Math.floor(Math.random() * 3)) return rsg(6 + Math.floor(Math.random() * 3))
} }

View file

@ -1,6 +1,6 @@
{ {
"botName": "botvX Dev", "botName": "botvX Dev",
"botVersion": "10.0.0-beta.2", "botVersion": "10.1.0-alpha.1",
"botAuthor": "a5a06d596f15c7db", "botAuthor": "a5a06d596f15c7db",
"isPreRelease": true, "isPreRelease": true,
"sourceURL": "https://code.chipmunk.land/7cc5c4f330d47060/botvX" "sourceURL": "https://code.chipmunk.land/7cc5c4f330d47060/botvX"