Compare commits

..

31 commits

Author SHA1 Message Date
ac9ce2d957 Update README.md 2024-09-20 00:06:33 -04:00
8ddee3cf3a
Backport README update to 10.0 branch 2024-09-20 00:04:32 -04:00
5a7a6548d7
Bump version 2024-09-13 03:50:03 -04:00
7ce5949d86
Bugfix 2024-09-13 03:49:00 -04:00
171b6a2f9a
Bump version 2024-09-12 00:19:03 -04:00
a85269ecce
Lint 2024-09-12 00:18:41 -04:00
28ebfc7b62
How did I not see this 2024-09-08 22:39:08 -04:00
f1994b7f7f
Improvements to about command 2024-09-08 22:24:36 -04:00
0b0fad42ef
Fix "info serveR 2024-09-08 22:24:02 -04:00
bf111d2648
Case sensitivity fixes 2024-09-08 22:23:22 -04:00
32852ff120
Update branding
If it causes problems, botvX
2024-09-08 22:06:35 -04:00
83d2cf4a65
Add m_c_player format 2024-09-08 22:06:29 -04:00
4cf86f31c1
Add chipmunk mod format 2024-09-08 22:06:25 -04:00
9658c63dcd
Change author 2024-08-30 21:46:25 -04:00
u0_a342
0f28a43a03 Update packages 2024-08-28 23:20:25 -04:00
81b6612233 Readme fix 2024-08-28 23:09:16 -04:00
08b6a1df01
README improvements 2024-08-28 20:16:14 -04:00
40c45b6935
Add provisional branding which is subject to change 2024-08-28 20:14:52 -04:00
a608d852dd
Lint 2024-08-25 22:31:09 -04:00
49485b1040
Allow bot owners to disable user settings 2024-08-25 22:27:39 -04:00
0147badad3
Remove settings location from example settings 2024-08-25 22:26:51 -04:00
cb4aa5a818
Hide hidden commands within specific command help 2024-08-25 22:26:33 -04:00
f6b2365ccd
Fix end portal bug with packets 2024-08-25 22:26:10 -04:00
314cfc9f85
Lint 2024-08-25 22:26:03 -04:00
831ed85c00
Add anti-spam system 2024-08-25 22:25:08 -04:00
2e19b33053
Add disable of incoming netmsg 2024-08-25 22:23:15 -04:00
e4dffbaad9
Make the name field in options useful (netmsg) 2024-08-25 07:12:23 -04:00
00a2a4f48f
Remove "Dev" label 2024-08-25 07:11:23 -04:00
5b4b7e8958
Disable parsing attempts for 4/8 bits 2024-08-25 07:10:49 -04:00
a473d15d4e
This is not a pre-release branch 2024-08-23 10:56:42 -04:00
60b2ba83e3
Serverinfo bugfix 2024-08-23 10:54:43 -04:00
57 changed files with 517 additions and 1201 deletions

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024-2025 7cc5c4f330d47060
Copyright (c) 2024 7cc5c4f330d47060
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View file

@ -7,11 +7,9 @@ owobot is a Minecraft bot originally designed for [Kaboom](https://kaboom.pw/) a
- a command core, to run commands quickly
- a hashing system, to enable trusted users to securely run certain commands in chat
It supports all Minecraft versions from 1.13 to 1.20.4 that are supported by node-minecraft-protocol.
If you are not sure if this code is safe to run, you can read through every line of code. You can also see the commit history by clicking on the (n) commits button, to make sure nobody added any exploits to the code.
If you are not sure if this code is safe to run, you can read through every line of code. You can also see the commit history by clicking on the (n) commits button, to make sure nobody has added any exploits or introduced vulnerabilities to the code.
If you find any exploits, security issues, etc in the code, please send me an issue or pull request and I will try to respond to it as soon as possible.
If you find any exploits, security issues, etc in the code, please send me an issue or pull request and I will try to respond to it whenever I see it.
## How to install?

34
commands/about.js Executable file → Normal file
View file

@ -1,7 +1,6 @@
const os = require('os')
const cp = require('child_process')
const { getMessage, formatTime } = require('../util/lang.js')
const memoryconvert = require('../util/memoryconvert.js')
const fs = require('fs')
const botVersion = require('../util/version.js')
const version = require('../version.json')
@ -29,10 +28,6 @@ const aboutBot = function (c) {
})
}
c.reply({ text: '' })
c.reply({
text: getMessage(c.lang, 'command.about.license'),
color: c.colors.secondary
})
c.reply({
translate: getMessage(c.lang, 'command.about.sourceCode'),
color: c.colors.secondary,
@ -160,21 +155,6 @@ const aboutServer = function (c) {
})
}
// System memory (total)
displayInfo('command.about.serverInfo.totalMem', () => {
return memoryconvert(os.totalmem())
})
// System memory (free)
displayInfo('command.about.serverInfo.freeMem', () => {
return memoryconvert(os.freemem())
})
// System memory (used)
displayInfo('command.about.serverInfo.usedMem', () => {
return memoryconvert(os.totalmem() - os.freemem())
})
// Username and UID
displayInfo('command.about.serverInfo.osUsername', () => {
return `${os.userInfo().username} (${os.userInfo().uid})`
@ -221,16 +201,10 @@ const aboutServer = function (c) {
}
const displayServerList = function (c) {
index.bots.forEach((item, i) => {
if (c.bot.id === i && c.bot.host.options.hideLocally) return
if (item.host.options && item.host.options.hidden && c.verify !== 2 && c.bot.id !== i) return
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'
let host = item.host.host
const port = item.host.port
if (item.host.options && item.host.options.displayAsIPv6) {
host = `[${host}]`
}
c.reply({
translate: getMessage(c.lang, message),
color: c.colors.secondary,
@ -240,11 +214,11 @@ const displayServerList = function (c) {
color: c.colors.primary
},
{
text: `${host}:${port}`,
text: `${item.host.host}:${item.host.port}`,
color: c.colors.primary,
clickEvent: {
action: 'copy_to_clipboard',
value: `${host}:${port}`
value: `${item.host.host}:${item.host.port}`
},
hoverEvent: {
action: 'show_text',

0
commands/cb.js Executable file → Normal file
View file

0
commands/cloop.js Executable file → Normal file
View file

40
commands/eval.js Executable file → Normal file
View file

@ -1,41 +1,11 @@
const index = require('../index.js') // Not used in the code, but may be used by users of the command
const { getMessage } = require('../util/lang.js')
module.exports = {
execute: (c) => {
const item = eval(c.args.join(' '))
if (c.type === 'console') {
console.log(item)
} else {
c.reply({
translate: '%s: %s',
color: c.colors.primary,
with: [
{
text: getMessage(c.lang, 'command.eval.output'),
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
}
}
}
]
})
try {
console.log(eval(c.args.join(' ')))
} catch (e) {
console.error(e)
}
},
level: 2
level: 3
}

115
commands/help.js Executable file → Normal file
View file

@ -1,11 +1,10 @@
const fs = require('fs')
const settings = require('../settings.json')
const cmds = Object.create(null)
const { getMessage } = require('../util/lang.js')
const sortHelp = function sortHelp (c1, c2) {
const level1 = cmds[c1.with[0].text].level ? cmds[c1.with[0].text].level : 0
const level2 = cmds[c2.with[0].text].level ? cmds[c2.with[0].text].level : 0
const level1 = cmds[c1.with[0]].level ? cmds[c1.with[0]].level : 0
const level2 = cmds[c2.with[0]].level ? cmds[c2.with[0]].level : 0
return level1 - level2
}
@ -16,7 +15,6 @@ for (const plugin of bpl) {
}
try {
const commandName = plugin.split('.js')[0]
if (commandName === 'settings' && settings.disableUserSettings) continue
if (commandName !== 'help') {
cmds[commandName] = require(`./${plugin}`)
if (cmds[commandName].level === undefined) {
@ -28,111 +26,39 @@ for (const plugin of bpl) {
const printHelp = (c) => {
const commandList = []
const permsN = getMessage(c.lang, 'command.help.permsNormal')
const permsT = getMessage(c.lang, 'command.help.permsTrusted')
const permsO = getMessage(c.lang, 'command.help.permsOwner')
const permList = [permsN, permsT, permsO]
const colorList = ['green', 'red', 'dark_red']
for (const i in cmds) {
if (cmds[i].hidden) continue
let cmdColor
if (colorList[cmds[i].level]) {
cmdColor = colorList[cmds[i].level]
} else {
cmdColor = colorList[0]
switch (cmds[i].level) {
case 0:
cmdColor = 'green'
break
case 1:
cmdColor = 'red'
break
case 2:
cmdColor = 'dark_red'
break
case 3:
cmdColor = 'dark_red'
break
default:
cmdColor = 'green'
}
let usage = getMessage(c.lang, `command.${i}.usage`).split('||')
let desc = getMessage(c.lang, `command.${i}.desc`)
if (cmds[i].usage) {
usage = cmds[i].usage.split('||')
}
if (cmds[i].desc) {
desc = cmds[i].desc
}
const hoverText = []
for (const item of usage) {
hoverText.push({
translate: getMessage(c.lang, 'command.help.commandUsage.lf'),
color: c.colors.secondary,
with: [
{
text: i,
color: c.colors.primary
},
{
text: item,
color: c.colors.primary
}
]
})
}
hoverText.push({
translate: getMessage(c.lang, 'command.help.commandDesc.lf'),
color: c.colors.secondary,
with: [
{
text: desc,
color: c.colors.primary
}
]
})
const rPerms = cmds[i].level ? cmds[i].level : 0
hoverText.push({
translate: getMessage(c.lang, 'command.help.commandPerms.lf'),
color: c.colors.secondary,
with: [
{
text: permList[rPerms],
color: c.colors.primary
}
]
})
hoverText.push({
translate: getMessage(c.lang, 'command.help.runCommand'),
color: c.colors.secondary
})
commandList.push(
{
translate: '%s ',
color: cmdColor,
with: [
{
text: i,
hoverEvent: {
action: 'show_text',
value: hoverText,
contents: hoverText
},
clickEvent: {
action: 'suggest_command',
value: `${c.prefix}${i}`
}
}
i
]
}
)
}
const permListFormat = []
permList.forEach((item, i) => {
permListFormat.push({
translate: i === permList.length - 1 ? '%s' : '%s ',
color: colorList[i],
with: [
item
]
})
})
c.reply({
translate: '%s %s',
with: [
{
translate: '%s (%s):',
with: [
getMessage(c.lang, 'command.help.cmdList'),
permListFormat
]
},
getMessage(c.lang, 'command.help.cmdList'),
commandList.sort(sortHelp)
]
})
@ -193,13 +119,14 @@ const printCmdHelp = (c) => {
const permsN = getMessage(c.lang, 'command.help.permsNormal')
const permsT = getMessage(c.lang, 'command.help.permsTrusted')
const permsO = getMessage(c.lang, 'command.help.permsOwner')
const permsC = getMessage(c.lang, 'command.help.permsConsole')
const rPerms = cmds[cmd].level ? cmds[cmd].level : 0
c.reply({
translate: getMessage(c.lang, 'command.help.commandPerms'),
color: c.colors.secondary,
with: [
{
text: [permsN, permsT, permsO][rPerms],
text: [permsN, permsT, permsO, permsC][rPerms],
color: c.colors.primary
}
]

0
commands/logoff.js Executable file → Normal file
View file

8
commands/netmsg.js Executable file → Normal file
View file

@ -1,4 +1,4 @@
const { bots } = require('../index.js')
const { bot } = require('../index.js')
const { getMessage } = require('../util/lang.js')
module.exports = {
execute: (c) => {
@ -7,8 +7,6 @@ module.exports = {
if (c.bot.host.options && c.bot.host.options.hidden) {
host = 'localhost' // Makes hidden servers appear as localhost
port = '25565'
} else if (c.bot.host.options && c.bot.host.options.displayAsIPv6) {
host = `[${host}]`
}
const json = {
translate: '[%s] %s: %s',
@ -43,12 +41,12 @@ module.exports = {
color: c.colors.primary
},
{
text: c.args.join(' ').slice(0, 512)
text: c.args.join(' ')
}
],
color: 'white'
}
bots.forEach(item => {
bot.forEach(item => {
if (item.host.options && item.host.options.netmsgIncomingDisabled && c.type !== 'console') return
item.tellraw('@a', json)
})

0
commands/refill.js Executable file → Normal file
View file

0
commands/restart.js Executable file → Normal file
View file

38
commands/say.js Executable file → Normal file
View file

@ -1,41 +1,7 @@
const settings = require('../settings.json')
const version = require('../version.json')
module.exports = {
execute: (c) => {
if (c.verify < 1) {
c.bot.tellraw('@a', {
translate: '%s %s: %s',
color: 'white',
with: [
{
translate: '[%s]',
color: 'white',
with: [
{
translate: '%s: %s',
color: settings.colors.secondary,
with: [
{
text: 'Prefix'
},
{
text: settings.prefix[0],
color: settings.colors.primary
}
]
}
]
},
{
text: version.botName,
color: settings.colors.primary
},
c.args.join(' ').slice(0, 512)
]
})
return
}
c.bot.chat(c.args.join(' ').slice(0, 512))
if (c.args[0].startsWith('/') && c.verify < 1) return
c.bot.chat(c.args.join(' '))
},
consoleIndex: true,
aliases: ['echo']

2
commands/settings.js Executable file → Normal file
View file

@ -10,7 +10,7 @@ module.exports = {
})
return
}
if (settings.disableUserSettings) {
if (settings.userSettingsDisabled) {
c.reply({
text: getMessage(c.lang, 'command.settings.disabled.global'),
color: c.colors.secondary

0
commands/stop.js Executable file → Normal file
View file

0
commands/template.js Executable file → Normal file
View file

1
commands/test.js Executable file → Normal file
View file

@ -37,7 +37,6 @@ module.exports = {
c.reply(reply('nickname', c.nickname))
c.reply(reply('command', c.command))
c.reply(reply('msgType', c.msgType))
c.reply(reply('msgSubtype', c.msgSubtype))
c.reply(reply('prefix', c.prefix))
c.reply(reply('args', c.args.join(', ')))
c.reply(reply('verify', c.verify.toString()))

3
commands/validate.js Executable file → Normal file
View file

@ -4,12 +4,13 @@ module.exports = {
const permsN = getMessage(c.lang, 'command.help.permsNormal')
const permsT = getMessage(c.lang, 'command.help.permsTrusted')
const permsO = getMessage(c.lang, 'command.help.permsOwner')
const permsC = getMessage(c.lang, 'command.help.permsConsole')
c.reply({
translate: getMessage(c.lang, 'command.verify.success'),
color: c.colors.secondary,
with: [
{
text: [permsN, permsT, permsO][c.verify],
text: [permsN, permsT, permsO, permsC][c.verify],
color: c.colors.primary
}
]

View file

@ -8,18 +8,14 @@ if (!fs.readdirSync('.').includes('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. It is also recommended to remove permissions of other users to read from this file, for example, by giving it 600 permissions if running on a Unix or Unix-like OS.')
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')
const secret = require('./secret.json')
const version = require('./version.json')
const protover = require('./util/getProtocolVersion.js')
const mcd = require('minecraft-data')
module.exports.bots = []
module.exports.bot = []
const botplug = []
const bpl = fs.readdirSync('plugins')
@ -36,69 +32,44 @@ const loadplug = (botno) => {
botplug.forEach((plug) => {
try {
if (plug.load) {
plug.load(module.exports.bots[botno])
plug.load(module.exports.bot[botno])
}
} catch (e) { console.log(e) }
})
}
let bypassWarningShown = false
const createBot = function createBot (host, oldId) {
if (host.options.disabled) {
return
}
const options = {
const bot = new EventEmitter()
bot._client = m.createClient({
host: host.host,
port: host.port ? host.port : 25565,
username: generateUser(host.options.legalName),
version: host.version ? host.version : settings.version_mc
}
if (protover(options.version) < version.minimumMcVersion) {
if (!settings.bypassVersionRequirement) {
console.error(`[error] ${version.botName} does not support Minecraft versions below ${version.minimumMcVersion} (${mcd.postNettyVersionsByProtocolVersion.pc[version.minimumMcVersion][0].minecraftVersion})`)
return
} else {
if (!bypassWarningShown) console.warn('[warning] You have disabled the version requirement, allowing the bot to join to servers with old Minecraft versions. These versions are unsupported and may break at any time. Any issues on such versions will not be fixed.')
bypassWarningShown = true
}
}
if (host.options.online) {
options.username = secret.onlineEmail
options.password = secret.onlinePass
options.auth = 'microsoft'
} else {
options.username = generateUser(host.options.legalName)
}
const bot = new EventEmitter()
bot._client = m.createClient(options)
})
if (typeof oldId !== 'undefined') {
for (const i in module.exports.bots[oldId].interval) {
clearInterval(module.exports.bots[oldId].interval[i])
for (const i in module.exports.bot[oldId].interval) {
clearInterval(module.exports.bot[oldId].interval[i])
}
delete module.exports.bots[oldId]
delete module.exports.bot[oldId]
bot.id = oldId
module.exports.bots[oldId] = bot
module.exports.bot[oldId] = bot
} else {
bot.id = module.exports.bots.length
module.exports.bots.push(bot)
bot.id = module.exports.bot.length
module.exports.bot.push(bot)
}
bot.host = host
if (bot.host.host.includes(':')) {
bot.host.options.displayAsIPv6 = true
}
bot.interval = {}
bot.info = (msg) => {
console.log(`[${bot.id}] [info] ${msg}`)
}
bot.displayChat = (type, subtype, msg) => {
if (settings.displaySubtypesToConsole) {
console.log(`[${bot.id}] [${type}] [${subtype}] ${msg}`)
} else {
console.log(`[${bot.id}] [${type}] ${msg}`)
}
bot.displayChat = (type, msg) => {
console.log(`[${bot.id}] [${type}] ${msg}`)
}
loadplug(bot.id)

17
lang/en-US.json Executable file → Normal file
View file

@ -48,7 +48,6 @@
"command.about.version": "Version %s",
"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.license": "This bot is free and open-source software and is available under the terms of the MIT license.",
"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.subcommand": "Unknown subcommand, please do %s",
@ -56,19 +55,15 @@
"command.cloop.success.remove": "Removed command loop %s",
"command.cloop.success.clear": "Cleared all command loops",
"command.cloop.list": "%s: Command: %s Rate: %s",
"command.eval.output": "Output",
"command.help.cmdList": "Commands",
"command.help.cmdList": "Commands:",
"command.help.commandInfo": "%s%s - %s",
"command.help.commandUsage": "Usage - %s%s",
"command.help.commandDesc": "Description - %s",
"command.help.commandPerms": "Required permissions - %s",
"command.help.commandUsage.lf": "Usage - %s%s\n",
"command.help.commandDesc.lf": "Description - %s\n",
"command.help.commandPerms.lf": "Required permissions - %s\n",
"command.help.runCommand": "Click to run command",
"command.help.permsNormal": "Public",
"command.help.permsNormal": "Normal",
"command.help.permsTrusted": "Trusted",
"command.help.permsOwner": "Owner",
"command.help.permsConsole": "Console",
"command.help.noCommand": "Command does not exist",
"command.help.alias": "Alias to %s",
"command.netmsg.disabled": "This command has been disabled on this server.",
@ -87,7 +82,6 @@
"command.test.nickname": "Nickname",
"command.test.command": "Command",
"command.test.msgType": "Message type",
"command.test.msgSubtype": "Message subtype",
"command.test.prefix": "Prefix",
"command.test.args": "Arguments",
"command.test.verify": "Permission level",
@ -106,9 +100,6 @@
"command.about.serverInfo.kernelVer": "Kernel version",
"command.about.serverInfo.processor": "CPU",
"command.about.serverInfo.arch": "Architecture",
"command.about.serverInfo.totalMem": "Total memory",
"command.about.serverInfo.freeMem": "Free memory",
"command.about.serverInfo.usedMem": "Used memory",
"command.about.serverInfo.osUsername": "Username",
"command.about.serverInfo.hostName": "Hostname",
"command.about.serverInfo.workingDir": "Working directory",
@ -126,7 +117,7 @@
"command.tpr.success": "Teleporting %s to %s, %s, %s",
"command.verify.success": "Successfully verified with permission level %s",
"command.error": "An error occured (check console for more info)",
"command.disallowed.perms": "You do not have permission to run this command. If you do have permission, please make sure you put the command hash at the end, or ran the command through the hashing system of your client or proxy.",
"command.disallowed.perms": "You do not have permission to run this command. If you do have permission, please make sure you put the command hash at the end, or ran the command through your client's hashing system.",
"command.disallowed.perms.yourLevel": "Your permission level: %s",
"command.disallowed.perms.cmdLevel": "Command requires: %s",
"copyText": "Click to copy!"

114
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "botv11",
"version": "11.0.0-alpha.2",
"name": "botv10",
"version": "10.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "botv11",
"version": "11.0.0-alpha.2",
"name": "botv10",
"version": "10.0.0",
"license": "MIT",
"dependencies": {
"minecraft-protocol": "^1.45.0",
@ -14,21 +14,21 @@
}
},
"node_modules/@azure/msal-common": {
"version": "14.15.0",
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.15.0.tgz",
"integrity": "sha512-ImAQHxmpMneJ/4S8BRFhjt1MZ3bppmpRPYYNyzeQPeFN288YKbb8TmmISQEbtfkQ1BPASvYZU5doIZOPBAqENQ==",
"version": "14.14.1",
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.14.1.tgz",
"integrity": "sha512-2Q3tqNz/PZLfSr8BvcHZVpRRfSn4MjGSqjj9J+HlBsmbf1Uu4P0WeXnemjTJwwx9KrmplsrN3UkZ/LPOR720rw==",
"license": "MIT",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@azure/msal-node": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.15.0.tgz",
"integrity": "sha512-gVPW8YLz92ZeCibQH2QUw96odJoiM3k/ZPH3f2HxptozmH6+OnyyvKXo/Egg39HAM230akarQKHf0W74UHlh0Q==",
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.13.0.tgz",
"integrity": "sha512-DhP97ycs7qlCVzzzWGzJiwAFyFj5okno74E4FUZ61oCLfKh4IxA1kxirqzrWuYZWpBe9HVPL6GA4NvmlEOBN5Q==",
"license": "MIT",
"dependencies": {
"@azure/msal-common": "14.15.0",
"@azure/msal-common": "14.14.1",
"jsonwebtoken": "^9.0.0",
"uuid": "^8.3.0"
},
@ -37,18 +37,18 @@
}
},
"node_modules/@types/node": {
"version": "22.8.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.4.tgz",
"integrity": "sha512-SpNNxkftTJOPk0oN+y2bIqurEXHTA2AOZ3EJDDKeJ5VzkvvORSvmQXGQarcOzWV1ac7DCaPBEdMDxBsM+d8jWw==",
"version": "22.5.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.1.tgz",
"integrity": "sha512-KkHsxej0j9IW1KKOOAA/XBA0z08UFSrRQHErzEfA3Vgq57eXIMYboIlHJuYIfd+lwCQjtKqUu3UnmKbtUc9yRw==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.8"
"undici-types": "~6.19.2"
}
},
"node_modules/@types/readable-stream": {
"version": "4.0.16",
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.16.tgz",
"integrity": "sha512-Fvp+8OcU8PyV90KTk5tR/rI8OjD3MP5NUow5rjOsZo+9zxf4p4soJtK9j4V6yeG30TH6rZxqRaP4JLa8lNNTNQ==",
"version": "4.0.15",
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.15.tgz",
"integrity": "sha512-oAZ3kw+kJFkEqyh7xORZOku1YAKvsFTogRY8kVl4vHpEKiDkfnSA/My8haRE7fvmix5Zyy+1pwzOi7yycGLBJw==",
"license": "MIT",
"dependencies": {
"@types/node": "*",
@ -189,12 +189,12 @@
"license": "MIT"
},
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
@ -257,9 +257,9 @@
"license": "MIT"
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
@ -296,6 +296,12 @@
],
"license": "BSD-3-Clause"
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/jose": {
"version": "4.15.9",
"resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
@ -421,9 +427,9 @@
"license": "MIT"
},
"node_modules/minecraft-data": {
"version": "3.78.0",
"resolved": "https://registry.npmjs.org/minecraft-data/-/minecraft-data-3.78.0.tgz",
"integrity": "sha512-Ssks8QD31lsoxqa7LySTqeP9romsfAbfsSGiUHiGMeqfxRi/PtOxGLyKD1BXB8V/tXLztFcbQYqzIhprDkPguw==",
"version": "3.68.0",
"resolved": "https://registry.npmjs.org/minecraft-data/-/minecraft-data-3.68.0.tgz",
"integrity": "sha512-pNBTi39a1zbFpN9itwi0YSL3hqAsSw38D7pE9C6m+aURmXljpBlNTO+TkpZxxDv4KqqtNBOhmkj4x46IDW6R+Q==",
"license": "MIT"
},
"node_modules/minecraft-folder-path": {
@ -433,9 +439,9 @@
"license": "MIT"
},
"node_modules/minecraft-protocol": {
"version": "1.50.0",
"resolved": "https://registry.npmjs.org/minecraft-protocol/-/minecraft-protocol-1.50.0.tgz",
"integrity": "sha512-GiZy8g4YG0iZEKifX6ulCyhVnTDGZ1gH0ouUdxjo6xkKwp4KOf+ptbBgZ8G5+WHCumrI91+v/JYU07uCvKdi0w==",
"version": "1.47.0",
"resolved": "https://registry.npmjs.org/minecraft-protocol/-/minecraft-protocol-1.47.0.tgz",
"integrity": "sha512-IHL8faXLLIWv1O+2v2NgyKlooilu/OiSL9orI8Kqed/rZvVOrFPzs2PwMAYjpQX9gxLPhiSU19KqZ8CjfNuqhg==",
"license": "BSD-3-Clause",
"dependencies": {
"@types/readable-stream": "^4.0.0",
@ -445,7 +451,7 @@
"endian-toggle": "^0.0.0",
"lodash.get": "^4.1.2",
"lodash.merge": "^4.3.0",
"minecraft-data": "^3.78.0",
"minecraft-data": "^3.55.0",
"minecraft-folder-path": "^1.2.0",
"node-fetch": "^2.6.1",
"node-rsa": "^0.4.2",
@ -453,7 +459,7 @@
"prismarine-chat": "^1.10.0",
"prismarine-nbt": "^2.5.0",
"prismarine-realms": "^1.2.0",
"protodef": "^1.17.0",
"protodef": "^1.8.0",
"readable-stream": "^4.1.0",
"uuid-1345": "^1.0.1",
"yggdrasil": "^1.4.0"
@ -478,9 +484,9 @@
"license": "BSD-3-Clause"
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"license": "MIT"
},
"node_modules/nearley": {
@ -580,12 +586,12 @@
}
},
"node_modules/prismarine-registry": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/prismarine-registry/-/prismarine-registry-1.10.0.tgz",
"integrity": "sha512-6TYQiZHtsJ87HsB2E0yamCFp77ZyyLT16OmW5iXB5V30yCPflhHvR5TR2IqISmmiRc2093BkHfiIhsOZaMatmQ==",
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/prismarine-registry/-/prismarine-registry-1.7.0.tgz",
"integrity": "sha512-yyva0FpWI078nNeMhx8ekVza5uUTYhEv+C+ADu3wUQXiG8qhXkvrf0uzsnhTgZL8BLdsi2axgCEiKw9qSKIuxQ==",
"license": "MIT",
"dependencies": {
"minecraft-data": "^3.70.0",
"minecraft-data": "^3.0.0",
"prismarine-nbt": "^2.0.0"
}
},
@ -599,15 +605,15 @@
}
},
"node_modules/protodef": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/protodef/-/protodef-1.17.0.tgz",
"integrity": "sha512-mnpNPV3xwu63u3NwZuXM1RCp979vjHxUGHzVrb6dxbvof5Fx+b8Rs0G0c3xtEuFDreGAMWS7VrlNkDUDBMsFWQ==",
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/protodef/-/protodef-1.15.0.tgz",
"integrity": "sha512-bZ2Omw8dT+DACjJHLrBWZlqN4MlT9g9oSpJDdkUAJOStUzgJp+Zn42FJfPUdwutUxjaxA0PftN0PDlNa2XbneA==",
"license": "MIT",
"dependencies": {
"lodash.get": "^4.4.2",
"lodash.reduce": "^4.6.0",
"protodef-validator": "^1.3.0",
"readable-stream": "^4.4.0"
"readable-stream": "^3.0.3"
},
"engines": {
"node": ">=14"
@ -625,6 +631,20 @@
"protodef-validator": "cli.js"
}
},
"node_modules/protodef/node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@ -756,6 +776,12 @@
"punycode": "^2.1.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",

View file

@ -3,8 +3,8 @@
"minecraft-protocol": "^1.45.0",
"prismarine-chat": "^1.10.0"
},
"name": "botv11",
"version": "11.0.0-alpha.2",
"name": "botv10",
"version": "10.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"

239
plugins/!chat.js Executable file
View file

@ -0,0 +1,239 @@
const settings = require('../settings.json')
const parsePlain = require('../util/chatparse_plain.js')
const parseConsole = require('../util/chatparse_console.js')
const parse1204 = require('../util/parseNBT.js')
const { getMessage } = require('../util/lang.js')
const convertChatStyleItem = (item) => {
const output = {}
for (const i in item) {
output[i] = item[i].value
}
return output
}
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 = {
load: (b) => {
b.messageCount = 0
b.chatDisabledUntil = 0
b.interval.antiSpam = setInterval(() => {
b.messageCount = 0
}, 4000)
b.messageTypes = []
b._client.on('registry_data', (data) => {
if (data.codec.value['minecraft:chat_type']) {
b.messageTypes = data.codec.value['minecraft:chat_type']
const nbtItems = data.codec.value['minecraft:chat_type'].value.value.value.value
nbtItems.forEach((item, i) => {
b.messageTypes[i] = convertChatTypeItem(item.element.value.chat.value)
})
}
})
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) => {
const messageType = b.messageTypes[data.type]
const json = { translate: messageType.translation_key, with: [] }
messageType.parameters.forEach((item, i) => {
if (item === 'content') {
if (messageType.translation_key === '%s') {
json.with[i] = parse1204(data.unsignedChatContent)
} else {
json.with[i] = data.plainMessage
}
} else if (item === 'sender') {
json.with[i] = parse1204(data.networkName)
} else if (item === 'target') {
json.with[i] = parse1204(data.networkTargetName)
}
})
for (const i in messageType.style) {
json[i] = messageType.style[i]
}
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) => {
const json = parse1204(data.content)
if (json.translate === '%s %s %s') { // ChipmunkMod format
if (json.with && json.with[1] && json.with[2]) {
const username = parsePlain(json.with[1])
const uuid = b.findUUID(username)
const nickname = b.findDisplayName(uuid)
const message = parsePlain(json.with[2].extra)
b.emit('chat', {
json,
type: 'system',
uuid,
message,
nickname,
username
})
} else {
b.emit('chat', {
json,
type: 'system',
uuid: '00000000-0000-0000-0000-000000000000',
message: '',
nickname: '',
username: ''
})
}
} else if (json.extra && json.extra[4] && json.extra[3] && json.extra[5] && json.extra[4].text === ' » ') { // ChipmunkMod format - m_c_player
const username = parsePlain(json.extra[3])
const uuid = b.findUUID(username)
const nickname = b.findDisplayName(uuid)
const message = parsePlain(json.extra[5])
b.emit('chat', {
json,
type: 'system',
uuid,
message,
nickname,
username
})
} else { // Generic system chat format
const parsed = parsePlain(json)
const split = parsed.split(': ')
const chatName = split.splice(0, 1)[0]
const chatNameSplit = chatName.split(' ')
const nickname = chatNameSplit[chatNameSplit.length - 1]
const username = b.findRealName(chatName)
const uuid = b.findUUID(username)
b.emit('chat', {
json,
type: 'system',
uuid,
message: split.join(': '),
nickname,
username
})
}
})
b._client.on('chat', (data) => { // Legacy chat for versions <1.19
const json = parse1204(data.message)
const parsed = parsePlain(json)
let chatName
let nickname
let username
let message
let uuid
if (json.translate === '%s %s %s') { // ChipmunkMod format
if (json.with && json.with[1] && json.with[2]) {
username = parsePlain(json.with[1])
uuid = b.findUUID(username)
nickname = b.findDisplayName(uuid)
message = parsePlain(json.with[2].extra)
}
} else if (json.extra && json.extra[4] && json.extra[3] && json.extra[5] && json.extra[4].text === ' » ') { // ChipmunkMod format - m_c_player
username = parsePlain(json.extra[3])
uuid = b.findUUID(username)
nickname = b.findDisplayName(uuid)
message = parsePlain(json.extra[5])
} else if (b.host.options.isVanilla && json.translate === 'chat.type.text') { // Servers without Extras chat
if (json.with && json.with.length >= 2) {
message = parsePlain(json.with[1])
username = parsePlain(json.with[0])
}
uuid = b.findUUID(username)
} else { // Servers with Extras chat, such as Kaboom
const split = parsed.split(': ')
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(': ')
}
if (data.uuid) uuid = data.uuid
b.emit('chat', {
json,
type: 'legacy',
uuid,
message,
nickname,
username
})
})
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 msgPlain = parsePlain(data.json)
if (settings.logJSONmessages) console.log(data.json)
if (msgPlain.endsWith('\n\n\n\n\nThe chat has been cleared')) return
if (msgPlain.startsWith('Command set: ')) return
b.emit('plainchat', msgPlain, data.type)
b.displayChat(data.type, `${msgConsole}\x1b[0m`)
})
}
}

View file

@ -1,194 +0,0 @@
const settings = require('../settings.json')
const parsePlain = require('../util/chatparse_plain.js')
const parseConsole = require('../util/chatparse_console.js')
const parse1204 = require('../util/parseNBT.js')
const { getMessage } = require('../util/lang.js')
const fs = require('fs')
const convertChatStyleItem = (item) => {
const output = {}
for (const i in item) {
output[i] = item[i].value
}
return output
}
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: {}
}
}
}
// Level 0: highly specific parsers for certain players
// Level 1: server chat format parsers
// Level 2: generic parsers
const parsers = [[], [], []]
const bpl = fs.readdirSync('plugins/chatParsers')
for (const plugin of bpl) {
if (!plugin.endsWith('.js')) {
continue
}
try {
const parser = require(`./chatParsers/${plugin}`)
parsers[parser.priority].push(parser.parse)
} catch (e) { console.log(e) }
}
module.exports = {
load: (b) => {
b.messageCount = 0
b.chatDisabledUntil = 0
b.interval.antiSpam = setInterval(() => {
b.messageCount = 0
}, 4000)
b.messageTypes = []
b._client.on('registry_data', (data) => {
if (data.codec.value['minecraft:chat_type']) {
b.messageTypes = data.codec.value['minecraft:chat_type']
const nbtItems = data.codec.value['minecraft:chat_type'].value.value.value.value
nbtItems.forEach((item, i) => {
b.messageTypes[i] = convertChatTypeItem(item.element.value.chat.value)
})
}
})
b._client.on('profileless_chat', (data) => {
let messageType = b.messageTypes[data.type]
if (messageType === undefined) messageType = { translation_key: '%s', parameters: ['content'] }
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]
}
const message = parsePlain(parse1204(data.message))
const uuid = b.findUUID(parsePlain(parse1204(data.name)))
const nickname = b.findDisplayName(uuid)
const username = parsePlain(parse1204(data.name))
b.emit('chat_unparsed', {
json,
type: 'profileless',
uuid,
message,
nickname,
username,
playerChatType: messageType
})
})
b._client.on('player_chat', (data) => {
let messageType = b.messageTypes[data.type]
if (messageType === undefined) messageType = { translation_key: '%s', parameters: ['content'] }
const json = { translate: messageType.translation_key, with: [] }
messageType.parameters.forEach((item, i) => {
if (item === 'content') {
if (messageType.translation_key === '%s') {
json.with[i] = parse1204(data.unsignedChatContent)
} else {
json.with[i] = data.plainMessage
}
} else if (item === 'sender') {
json.with[i] = parse1204(data.networkName)
} else if (item === 'target') {
json.with[i] = parse1204(data.networkTargetName)
}
})
for (const i in messageType.style) {
json[i] = messageType.style[i]
}
b.emit('chat_unparsed', {
json,
type: 'player',
uuid: data.senderUuid,
message: data.plainMessage,
nickname: parsePlain(parse1204(data.networkName)),
username: b.findRealNameFromUUID(data.senderUuid),
playerChatType: messageType
})
})
b._client.on('system_chat', (data) => {
const json = parse1204(data.content)
b.emit('chat_unparsed', {
json,
type: 'system',
uuid: '00000000-0000-0000-0000-000000000000',
message: '',
nickname: '',
username: '',
playerChatType: {}
})
})
b._client.on('chat', (data) => { // Legacy chat for versions <1.19
const json = parse1204(data.message)
let nickname
let username
let message
let uuid
if (data.uuid) uuid = data.uuid
b.emit('chat_unparsed', {
json,
type: 'legacy',
uuid,
message,
nickname,
username,
playerChatType: {}
})
})
b.on('chat_unparsed', (data) => {
for (const lvl of parsers) {
for (const item of lvl) {
const output = item(data, b)
if (output.parsed) {
b.emit('chat', output)
return
}
}
}
b.emit('chat', {
parsed: true,
json: data.json,
type: data.type,
subtype: 'fallback',
uuid: '00000000-0000-0000-0000-000000000000',
message: '',
nickname: '',
username: ''
})
})
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 msgPlain = parsePlain(data.json)
if (settings.logJSONmessages) console.log(data.json)
if (msgPlain.endsWith('\n\n\n\n\nThe chat has been cleared')) return
if (msgPlain.startsWith('Command set: ')) return
b.emit('plainchat', msgPlain, data.type, data.subtype)
b.displayChat(data.type, data.subtype, `${msgConsole}\x1b[0m`)
})
}
}

View file

@ -1,47 +0,0 @@
const parsePlain = require('../../util/chatparse_plain.js')
module.exports = {
parse: (data, b) => {
if (data.type === 'system' || data.type === 'legacy') {
if (data.json.translate === '%s %s %s' || data.json.translate === '[%s] %s %s') {
let subtype = 'chipmunkmod_'
if (data.json.translate === '%s %s %s') {
subtype += 'name3'
} else if (data.json.translate === '[%s] %s %s') {
subtype += 'chomens'
}
if (data.json.with && data.json.with[1] && data.json.with[2]) {
const username = parsePlain(data.json.with[1])
const uuid = b.findUUID(username)
const nickname = b.findDisplayName(uuid)
const message = parsePlain(data.json.with[2].extra)
return {
parsed: true,
json: data.json,
type: data.type,
subtype,
uuid,
message,
nickname,
username
}
} else {
subtype += '_invalid'
return {
parsed: true,
json: data.json,
type: data.type,
subtype,
uuid: '00000000-0000-0000-0000-000000000000',
message: '',
nickname: '',
username: ''
}
}
}
}
return {
parsed: false
}
},
priority: 0
}

View file

@ -1,27 +0,0 @@
const parsePlain = require('../../util/chatparse_plain.js')
module.exports = {
parse: (data, b) => {
if (data.type === 'system' || data.type === 'legacy') {
if (data.json.extra && data.json.extra[4] && data.json.extra[3] && data.json.extra[5] && data.json.extra[4].text === ' » ') { // ChipmunkMod format - m_c_player
const username = parsePlain(data.json.extra[3])
const uuid = b.findUUID(username)
const nickname = b.findDisplayName(uuid)
const message = parsePlain(data.json.extra[5])
return {
parsed: true,
json: data.json,
type: data.type,
subtype: 'chipmunkmod_mcp',
uuid,
message,
nickname,
username
}
}
}
return {
parsed: false
}
},
priority: 0
}

View file

@ -1,31 +0,0 @@
const parsePlain = require('../../util/chatparse_plain.js')
module.exports = {
parse: (data, b) => {
if (data.type === 'profileless') {
if (data.playerChatType.translation_key === '%s') {
const parsed = parsePlain(data.json)
const split = parsed.split(': ')
const chatName = split.splice(0, 1)[0]
const chatNameSplit = chatName.split(' ')
const nickname = chatNameSplit[chatNameSplit.length - 1]
const username = b.findRealName(chatName)
const uuid = b.findUUID(username)
const message = split.join(': ')
return {
parsed: true,
json: data.json,
type: data.type,
subtype: 'extras_profileless',
uuid,
message,
nickname,
username
}
}
}
return {
parsed: false
}
},
priority: 1
}

View file

@ -1,20 +0,0 @@
module.exports = {
parse: (data, b) => {
if (data.type === 'player' || data.type === 'profileless') {
return {
parsed: true,
json: data.json,
type: data.type,
subtype: 'generic_player',
uuid: data.uuid,
message: data.message,
nickname: data.nickname,
username: data.username
}
}
return {
parsed: false
}
},
priority: 2
}

View file

@ -1,40 +0,0 @@
const parsePlain = require('../../util/chatparse_plain.js')
module.exports = {
parse: (data, b) => {
if (data.type === 'system' || data.type === 'legacy') {
let subtype = 'generic_system'
if (data.type === 'legacy' && data.uuid) subtype += '_withuuid'
const parsed = parsePlain(data.json)
const split = parsed.split(': ')
const chatName = split.splice(0, 1)[0]
const chatNameSplit = chatName.split(' ')
let uuid
let username
let nickname
if (data.uuid) {
uuid = data.uuid
username = b.findRealNameFromUUID(uuid)
nickname = b.findDisplayName(uuid)
} else {
nickname = chatNameSplit[chatNameSplit.length - 1]
username = b.findRealName(chatName)
uuid = b.findUUID(username)
}
return {
parsed: true,
json: data.json,
type: data.type,
subtype,
uuid,
message: split.join(': '),
nickname,
username
}
}
return {
parsed: false
}
},
priority: 2
}

View file

@ -1,33 +0,0 @@
const parsePlain = require('../../util/chatparse_plain.js')
module.exports = {
parse: (data, b) => {
if (data.type === 'legacy') {
let subtype = 'vanilla_legacy'
if (data.type === 'legacy' && data.uuid) subtype += '_withuuid'
if (data.json.translate === 'chat.type.text') { // Servers without Extras chat
let message
let username
if (data.json.with && data.json.with.length >= 2) {
message = parsePlain(data.json.with[1])
username = parsePlain(data.json.with[0])
}
const uuid = b.findUUID(username)
const nickname = b.findDisplayName(uuid)
return {
parsed: true,
json: data.json,
type: data.type,
subtype,
uuid,
message,
nickname,
username
}
}
}
return {
parsed: false
}
},
priority: 1
}

View file

@ -25,8 +25,8 @@ module.exports = {
b.on('plainchat', (msg, type) => {
if (!settings.disableLogging && !settings.disableChatLogging) chatlog(`chat_${b.host.host}_${b.host.port}`, `[${type}] ${msg}`)
})
b.on('command', c => {
if (!settings.disableLogging && !settings.disableCommandLogging) chatlog(`cmd_${b.host.host}_${b.host.port}`, `[${c.msgType}] ${c.username} (${c.uuid}): ${c.command}`)
b.on('command', (name, uuid, text) => {
if (!settings.disableLogging && !settings.disableCommandLogging) chatlog(`cmd_${b.host.host}_${b.host.port}`, `${name} (${uuid}): ${text}`)
})
}
}

View file

@ -1,14 +1,15 @@
const Command = require('../util/Command.js')
const hashcheck = require('../util/hashcheck.js')
const settings = require('../settings.json')
const { getMessage } = require('../util/lang.js')
const cmds = require('../util/commands.js')
const fs = require('fs')
if (!fs.readdirSync('.').includes('userPref') && !settings.disableUserSettings) fs.mkdirSync('userPref')
if (!fs.readdirSync('.').includes('userPref') && !settings.userSettingsDisabled) fs.mkdirSync('userPref')
const loadSettings = function (uuid) {
try {
if (settings.disableUserSettings) {
if (settings.userSettingsDisabled) {
return {}
} else {
return require(`../userPref/${uuid}.json`)
@ -19,30 +20,45 @@ const loadSettings = function (uuid) {
}
module.exports = {
load: (b) => {
b.prefix = settings.prefix
b.lastCmd = 0
b.on('chat', (data) => {
const fullCommand = data.message
for (const prefix of settings.prefix) {
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, data.subtype, prefix)
b.runCommand(data.username, data.nickname, data.uuid, command, data.type, prefix)
}
}
})
b.runCommand = (name, nickname, uuid, text, msgType, msgSubtype, prefix) => {
b.runCommand = (name, nickname, uuid, text, msgType, prefix) => {
if (uuid === '00000000-0000-0000-0000-000000000000') return
if (Date.now() - b.lastCmd <= 1000) return
const userSettings = loadSettings(uuid)
b.lastCmd = Date.now()
const cmd = text.split(' ')
const lang = settings.defaultLang
const commandClass = new Command(uuid, name, nickname, text, msgType, msgSubtype, prefix, b, userSettings)
b.emit('command', commandClass)
if (commandClass.cancel === true) return
if (cmds[commandClass.cmdName.toLowerCase()]) {
const verify = hashcheck(cmd)
if (verify > 0) {
text = cmd.slice(0, cmd.length - 1).join(' ')
}
b.emit('command', name, uuid, text, prefix)
if (cmds[cmd[0].toLowerCase()]) {
const command = cmds[cmd[0].toLowerCase()]
if (command.level !== undefined && command.level > verify) {
b.tellraw(uuid, {
text: getMessage(lang, 'command.disallowed.perms')
})
b.tellraw(uuid, {
text: getMessage(lang, 'command.disallowed.perms.yourLevel', [verify + ''])
})
b.tellraw(uuid, {
text: getMessage(lang, 'command.disallowed.perms.cmdLevel', [command.level + ''])
})
return
}
try {
cmds[commandClass.cmdName.toLowerCase()].execute(commandClass)
cmds[cmd[0].toLowerCase()].execute(new Command(uuid, name, nickname, text, msgType, prefix, b, verify, userSettings))
} catch (e) {
console.log(e)
b.tellraw(uuid, {

View file

@ -1,6 +1,4 @@
const uuidToInt = require('../util/uuidtoint.js')
const plainParser = require('../util/chatparse_plain.js')
const mcParser = require('../util/chatparse_mc.js')
const cs = {
x: 4,
y: 6,
@ -19,7 +17,6 @@ module.exports = {
b.refillCoreCmd = `/fill ~ 55 ~ ~${cs.x - 1} ${54 + cs.y} ~${cs.z - 1} command_block{CustomName:'{"translate":"%s %s","with":[{"translate":"entity.minecraft.ender_dragon"},{"translate":"language.region"}],"color":"#FFAAEE"}'}`
b.advanceccq = function () {
if (b.host.options.useChat) return
if (b.ccq[0] && b.ccq[0].length !== 0) {
b._client.write('update_command_block', {
command: '/',
@ -66,20 +63,18 @@ module.exports = {
skinParts: 127, // Allow the second layer of the skin, when the bot is sudoed to do /skin
mainHand: 1 // Right hand
})
if (!b.host.options.useChat) {
b.add_sc_task('cc', () => {
b.chat(b.refillCoreCmd)
}, true)
b.add_sc_task('cc_size', () => {
b.chat('/gamerule commandModificationBlockLimit 32768')
})
}
b.add_sc_task('cc', () => {
b.chat(b.refillCoreCmd)
}, true)
b.add_sc_task('cc_size', () => {
b.chat('/gamerule commandModificationBlockLimit 32768')
})
})
b.on('ccstart', () => {
setTimeout(() => { b.interval.ccqi = setInterval(b.advanceccq, 2) }, 1000)
b.ccStarted = true
})
b.on('chat_unparsed', (data) => {
b.on('chat', (data) => {
if (data.json.translate === 'commands.fill.failed' || (data.json.extra && data.json.extra[0] && data.json.extra[0].translate === 'commands.fill.failed') ||
data.json.translate === 'commands.fill.success' || (data.json.extra && data.json.extra[0] && data.json.extra[0].translate === 'commands.fill.success')) {
if (!b.ccStarted) {
@ -112,28 +107,20 @@ module.exports = {
b.tellraw = (uuid, message) => {
let finalname = ''
if (b.host.options.useChat) {
if (b.host.options.useAmpersandColorCodes) {
b.chat(mcParser(message).replaceAll('§', '&'))
} else {
b.chat(plainParser(message))
}
if (uuid === '@a') {
finalname = '@a'
} else if (uuid.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)) {
finalname = `@a[nbt={UUID:[I;${uuidToInt(uuid)}]}]`
} else {
if (uuid === '@a') {
finalname = '@a'
} else if (uuid.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)) {
finalname = `@a[nbt={UUID:[I;${uuidToInt(uuid)}]}]`
} else {
finalname = uuid
}
let tellrawCommand
if (b.host.options.isVanilla) {
tellrawCommand = 'tellraw'
} else {
tellrawCommand = 'minecraft:tellraw'
}
b.ccq.push(`/${tellrawCommand} ${finalname} ${JSON.stringify(message)}`)
finalname = uuid
}
let tellrawCommand
if (b.host.options.isVanilla) {
tellrawCommand = 'tellraw'
} else {
tellrawCommand = 'minecraft:tellraw'
}
b.ccq.push(`/${tellrawCommand} ${finalname} ${JSON.stringify(message)}`)
}
}
}

11
plugins/console.js Executable file → Normal file
View file

@ -2,7 +2,6 @@ const readln = require('readline')
const index = require('../index.js')
const ConsoleCommand = require('../util/ConsoleCommand.js')
const cmds = require('../util/commands.js')
const settings = require('../settings.json')
const rl = readln.createInterface({
input: process.stdin,
output: process.stdout,
@ -15,7 +14,7 @@ rl.on('line', (l) => {
const tmpcmd = l.split(' ')
const index2 = tmpcmd.splice(1, 1)[0]
if (index2 === '*') {
for (let i = 0; i < index.bots.length; i++) {
for (let i = 0; i < index.bot.length; i++) {
const cmd = new ConsoleCommand(tmpcmd.join(' '), i)
cmds[l.split(' ')[0].toLowerCase()].execute(cmd)
}
@ -46,12 +45,8 @@ module.exports = {
b.info = (msg) => {
consoleWrite(`[${b.id}] [info] ${msg}`)
}
b.displayChat = (type, subtype, msg) => {
if (settings.displaySubtypesToConsole) {
consoleWrite(`[${b.id}] [${type}] [${subtype}] ${msg}`)
} else {
consoleWrite(`[${b.id}] [${type}] ${msg}`)
}
b.displayChat = (type, msg) => {
consoleWrite(`[${b.id}] [${type}] ${msg}`)
}
}
}

View file

@ -8,11 +8,10 @@ module.exports = {
}
}, 100)
})
b.matcherRegex = /.{1,255}/g
b.chatqueue = []
b.chat = function chat (msg) {
if (msg.length === 0) return
msg.match(b.matcherRegex).forEach(element => {
msg.match(/.{1,255}/g).forEach(element => {
b.chatqueue.push(element)
})
}

View file

@ -1,31 +0,0 @@
const cmds = require('../util/commands.js')
const { getMessage } = require('../util/lang.js')
const hashcheck = require('../util/hashcheck.js')
module.exports = {
load: (b) => {
b.on('command', c => {
const cmd = c.command.split(' ')
const command = cmds[c.cmdName.toLowerCase()]
const verify = hashcheck(cmd, c.uuid)
const permsN = getMessage(c.lang, 'command.help.permsNormal')
const permsT = getMessage(c.lang, 'command.help.permsTrusted')
const permsO = getMessage(c.lang, 'command.help.permsOwner')
if (command && command.level !== undefined && command.level > verify) {
b.tellraw(c.uuid, {
text: getMessage(c.lang, 'command.disallowed.perms')
})
b.tellraw(c.uuid, {
text: getMessage(c.lang, 'command.disallowed.perms.yourLevel', [[permsN, permsT, permsO][verify]])
})
b.tellraw(c.uuid, {
text: getMessage(c.lang, 'command.disallowed.perms.cmdLevel', [[permsN, permsT, permsO][command.level]])
})
c.cancel = true
} else if (verify > 0) {
c.rewriteCommand(cmd.slice(0, cmd.length - 1).join(' '))
c.verify = verify
}
})
}
}

25
plugins/player.js Executable file → Normal file
View file

@ -28,17 +28,8 @@ module.exports = {
}
for (const uuid in buffer2) {
if (!b.players[uuid]) b.players[uuid] = { displayName: '', realName: '' }
let displayName = ''
let realName = ''
if (buffer2[uuid].displayName) {
displayName = buffer2[uuid].displayName
b.players[uuid].displayName = buffer2[uuid].displayName
}
if (buffer2[uuid].realName) {
realName = buffer2[uuid].realName
b.players[uuid].realName = buffer2[uuid].realName
}
b.emit('playerdata', uuid, displayName, realName)
if (buffer2[uuid].displayName) b.players[uuid].displayName = buffer2[uuid].displayName
if (buffer2[uuid].realName) b.players[uuid].realName = buffer2[uuid].realName
}
})
b.findUUID = (name) => {
@ -57,16 +48,16 @@ module.exports = {
}
return '[[[[ no name ]]]]'
}
b.findRealNameFromUUID = (uuid) => {
if (b.players[uuid]) {
return b.players[uuid].realName
b.findRealNameFromUUID = (name) => {
if (b.players[name]) {
return b.players[name].realName
} else {
return '[[[[ no name ]]]]'
}
}
b.findDisplayName = (uuid) => {
if (b.players[uuid]) {
const displayName = b.players[uuid].displayName.split(' ')
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

@ -1,7 +1,3 @@
const parsePlain = require('../util/chatparse_plain.js')
const parseMc = require('../util/chatparse_mc_withHex.js')
const settings = require('../settings.json')
const version = require('../version.json')
class SCTask {
constructor (failTask, startFailed = false) {
/*
@ -16,19 +12,17 @@ module.exports = {
load: (b) => {
b.sc_tasks = {}
b.selfcareRun = 0
b._client.on('login', () => {
b.interval.sc = setInterval(() => {
if (Date.now() - b.selfcareRun <= 600) {
return
b.interval.sc = setInterval(() => {
if (Date.now() - b.selfcareRun <= 600) {
return
}
for (const i in b.sc_tasks) {
if (b.sc_tasks[i].failed) {
b.sc_tasks[i].failTask()
}
for (const i in b.sc_tasks) {
if (b.sc_tasks[i].failed) {
b.sc_tasks[i].failTask()
b.selfcareRun = Date.now()
}
}
}, 40)
})
}
b.selfcareRun = Date.now()
}, 40)
b.add_sc_task = (name, failTask, startFailed) => {
b.sc_tasks[name] = new SCTask(failTask, startFailed)
}
@ -83,53 +77,11 @@ module.exports = {
b._client.write('client_command', { actionId: 0 }) // Simulates respawning
b.sc_tasks.respawn.failed = 0
})
b.on('chat_unparsed', (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') ||
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
}
})
// Prefix tablist ads
if (!b.host.options.isVanilla) {
b.adPrefix = {
translate: '[%s] %s', // Since the bot aims to have an invisible name, the ad prefix should contain information about the bot.
color: 'white',
with: [
{
translate: '%s: %s',
color: settings.colors.secondary,
with: [
{
text: 'Prefix'
},
{
text: settings.prefix[0],
color: settings.colors.primary
}
]
},
{
text: version.botName,
color: settings.colors.primary
}
]
}
b.add_sc_task('playerlist_ads', () => {
b.chat(`/prefix ${parseMc(b.adPrefix).replaceAll('§', '&')}`)
})
b.on('playerdata', (uuid, displayName) => {
if (uuid === b._client.uuid && !displayName.startsWith(parsePlain(b.adPrefix))) {
b.sc_tasks.playerlist_ads.failed = 1
}
})
b.on('plainchat', (msg) => {
if (msg === `You now have the tag: ${parseMc(b.adPrefix).replaceAll('§', '&')}` ||
msg === 'Something went wrong while saving the prefix. Please check console.') { // Fix the prefix issue
b.sc_tasks.playerlist_ads.failed = 0
}
})
}
}
}

0
secret_example.json Executable file → Normal file
View file

12
util/Command.js Executable file → Normal file
View file

@ -1,6 +1,6 @@
const settings = require('../settings.json')
class Command {
constructor (uuid, user, nick, cmd, msgType, msgSubtype, prefix, bot, prefs) {
constructor (uuid, user, nick, cmd, msgType, prefix, bot, verify, prefs) {
this.send = (text, uuid) => { bot.tellraw(uuid || '@a', text) }
this.reply = text => bot.tellraw(uuid, text)
this.uuid = uuid
@ -8,18 +8,16 @@ class Command {
this.nickname = nick
this.command = cmd
this.msgType = msgType
this.msgSubtype = msgSubtype
this.prefix = prefix
this.bot = bot
this.type = 'minecraft'
this.args = cmd.split(' ').slice(1)
this.cmdName = cmd.split(' ')[0]
this.verify = 0
this.verify = verify
this.host = bot.host.host
this.port = bot.host.port
this.serverName = bot.host.options.name
this.prefs = prefs
this.cancel = false
if (prefs.lang) {
this.lang = prefs.lang
} else {
@ -38,12 +36,6 @@ class Command {
_colors.secondary = settings.colors.secondary
}
this.colors = _colors
this.rewriteCommand = newCmd => {
this.command = newCmd
this.args = newCmd.split(' ').slice(1)
this.cmdName = newCmd.split(' ')[0]
}
}
}

6
util/ConsoleCommand.js Executable file → Normal file
View file

@ -11,19 +11,17 @@ class ConsoleCommand {
this.nickname = 'Owner'
this.command = cmd
this.msgType = '_bot_console'
this.msgSubtype = '_bot_console'
this.prefix = ''
this.bot = index2 >= 0
? index.bots[index2]
? index.bot[index2]
: {}
this.type = 'console'
this.args = cmd.split(' ').slice(1)
this.cmdName = cmd.split(' ')[0]
this.verify = 2
this.verify = 3
this.host = ''
this.port = '3'
this.serverName = `${version.botName} Console`
this.cancel = false
this.lang = settings.defaultLang
this.colors = settings.colors
}

0
util/chatlog.js Executable file → Normal file
View file

48
util/chatparse_console.js Executable file → Normal file
View file

@ -11,45 +11,19 @@ if (_consoleColors[settings.terminalMode]) {
consoleColors = _consoleColors.none.fourBit
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) => {
if (!consoleColors24.enabled || consoleColors24.bit === 4) { // Hex color parsing to the 4 bit mode has not been implemented yet
return ''
}
if (consoleColors24.bit === 24) {
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 < 64 && greenChannel < 64 && blueChannel < 64) {
out += '48;2;220;220;220;'
} 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`
if (!consoleColors24.enabled) return ''
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 < 64 && greenChannel < 64 && blueChannel < 64) {
out += '48;2;220;220;220;'
} 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`
}
const processColor = (col, rcol) => {

View file

@ -1,96 +0,0 @@
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,98 +0,0 @@
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 if (col.startsWith('#')) {
out = `§${col}`
} 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

10
util/chatparse_plain.js Executable file → Normal file
View file

@ -29,12 +29,10 @@ const parse = function (_data, l = 0) {
if (lang[trans] !== undefined) {
trans = lang[trans].replace(/%%/g, '\ue123')
}
if (data.with) {
data.with.forEach((item, i) => {
const j2 = parse(item, l + 1)
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'))
})
for (const i in data.with) {
const j2 = parse(data.with[i], l + 1)
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')
}

2
util/commands.js Executable file → Normal file
View file

@ -1,5 +1,4 @@
const fs = require('fs')
const settings = require('../settings.json')
const cmds = Object.create(null)
const bpl = fs.readdirSync('./commands')
for (const plugin of bpl) {
@ -8,7 +7,6 @@ for (const plugin of bpl) {
}
try {
const commandName = plugin.split('.js')[0]
if (commandName === 'settings' && settings.disableUserSettings) continue
cmds[commandName] = require(`../commands/${plugin}`)
if (cmds[commandName].level === undefined) {
cmds[commandName].level = 0

84
util/consolecolors.json Executable file → Normal file
View file

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

View file

@ -1,4 +0,0 @@
const mcd = require('minecraft-data')
module.exports = function (ver) {
return mcd.versionsByMinecraftVersion.pc[ver].version
}

6
util/hashcheck.js Executable file → Normal file
View file

@ -1,11 +1,11 @@
const crypto = require('crypto')
const secret = require('../secret.json')
module.exports = function (cmd, uuid) {
module.exports = function (cmd) {
const cmdWithoutHash = cmd.slice(0, cmd.length - 1).join(' ')
const _dateString = Date.now().toString()
const dateString = _dateString.slice(0, _dateString.length - 4)
const hashTrusted = `babyboom:${secret.keyTrusted}:${uuid}:${cmdWithoutHash}:${dateString}`
const hashOwner = `babyboom:${secret.keyOwner}:${uuid}:${cmdWithoutHash}:${dateString}`
const hashTrusted = `babyboom:${secret.keyTrusted}:${cmdWithoutHash}:${dateString}`
const hashOwner = `babyboom:${secret.keyOwner}:${cmdWithoutHash}:${dateString}`
const validhashT = crypto.createHash('sha256').update(hashTrusted).digest('hex')
const validhashO = crypto.createHash('sha256').update(hashOwner).digest('hex')
if (cmd[cmd.length - 1] === validhashT) {

6
util/lang.js Executable file → Normal file
View file

@ -1,7 +1,5 @@
const fs = require('fs')
const languages = {}
const settings = require('../settings.json')
const fallbackLocale = settings.fallbackLocale ? settings.fallbackLocale : 'en-US'
const loadplug = (botno) => {
const bpl = fs.readdirSync('lang')
@ -20,8 +18,8 @@ const getMessage = function (l, msg, with2) {
let message = msg.replace(/%%/g, '\ue123')
if (languages[l] && languages[l][message] !== undefined) {
message = languages[l][message].replace(/%%/g, '\ue123')
} else if (languages[fallbackLocale] && languages['en-US'][message] !== undefined) {
message = languages[fallbackLocale][message].replace(/%%/g, '\ue123')
} else if (languages['en-US'] && languages['en-US'][message] !== undefined) {
message = languages['en-US'][message].replace(/%%/g, '\ue123')
}
if (with2) {
with2.forEach((withItem, i) => {

0
util/mc_lang.js Executable file → Normal file
View file

View file

@ -1,15 +0,0 @@
module.exports = function (bytes) {
if (bytes >= 1125899906842624) { // Petabytes
return `${Math.round(bytes / 1125899906842624 * 100) / 100} PB`
} else if (bytes >= 1099511627776) { // Terabytes
return `${Math.round(bytes / 1099511627776 * 100) / 100} TB`
} else if (bytes >= 1073741824) { // Gigabytes
return `${Math.round(bytes / 1073741824 * 100) / 100} GB`
} else if (bytes >= 1048576) { // Megabytes
return `${Math.round(bytes / 1048576 * 100) / 100} MB`
} else if (bytes >= 1024) { // Kilobytes
return `${Math.round(bytes / 1024 * 100) / 100} KB`
} else { // Bytes
return `${bytes} B`
}
}

0
util/parseNBT.js Executable file → Normal file
View file

11
util/usergen.js Executable file → Normal file
View file

@ -2,17 +2,20 @@ const crypto = require('crypto')
const rsg = function (count) {
let output = ''
for (let i = 0; i < count; i++) {
const type = Math.floor(Math.random() * 5)
const type = Math.floor(Math.random() * 6)
switch (type) {
case 0:
output += '§§'
output += ' '
break
case 1:
output += '
output += §'
break
case 2:
output += '§ '
break
case 3:
case 4:{ // Make this case more likely
case 4:
case 5:{ // Make this case more likely
let rng = Math.floor(Math.random() * 16) + 1
if (rng === 7) rng = 17 // No bells
if (rng === 10) rng = 18 // No line feeds

0
util/uuidtoint.js Executable file → Normal file
View file

0
util/version.js Executable file → Normal file
View file

11
version.json Executable file → Normal file
View file

@ -1,8 +1,7 @@
{
"botName": "UBot Dev",
"botVersion": "11.0.0-alpha.2",
"botAuthor": "uwu1104090889",
"isPreRelease": true,
"sourceURL": "https://code.chipmunk.land/7cc5c4f330d47060/owobot",
"minimumMcVersion": 393
"botName": "owobot",
"botVersion": "10.0.3",
"botAuthor": "SundanceNanshan",
"isPreRelease": false,
"sourceURL": "https://code.chipmunk.land/7cc5c4f330d47060/owobot"
}