Compare commits

...

134 commits

Author SHA1 Message Date
aed4d9691f Update copyright year 2025-01-01 00:04:07 -05:00
2e036d5880
Selfcare fixes 2024-10-30 14:11:49 -04:00
3ae93be9ce
Update packages 2024-10-30 13:59:01 -04:00
cb5628ec25
Lint 2024-10-30 13:58:11 -04:00
04b6ccba63
Fix the bug with pefix 2024-10-30 13:57:22 -04:00
75e48f2103
Disable local server hiding message (it still hides the server, it just doesn't notify the user now) 2024-10-12 02:29:11 -04:00
a894dfd133
Change the package name to (almost) the codename (botvXI) for the next version (it most likely will not stay as owobot) 2024-10-12 01:47:39 -04:00
d79167b3f9
Update packages 2024-10-12 01:45:36 -04:00
9e48e9b6ea
Lint 2024-10-12 01:44:33 -04:00
f9e076fe91
Make the bot's name appear in the tablist 2024-10-12 01:43:46 -04:00
e05e58f867
Remove bot.prefix 2024-10-12 01:35:09 -04:00
a3835de35c
Say command improvements 2024-10-12 01:33:00 -04:00
f2fd8bc486
Restore old eval functionality for console only (players can still see with formatting) 2024-10-12 01:31:41 -04:00
57f44cc73d
Make all usernames appear as zero-length 2024-10-12 01:19:36 -04:00
ebf052234e
Provisional rebrand back to UBot 2024-10-12 01:07:38 -04:00
2b3e4789c6
Add local hiding of server IPs in the server command 2024-10-03 15:05:22 -04:00
1be6ea282e
Remove code relating to legacy versions 2024-09-22 23:52:56 -04:00
d1573a1305
Update version bypass warning 2024-09-22 23:50:13 -04:00
cfb19faee6
Change minimum version to 1.13 and make it configurable 2024-09-22 23:45:18 -04:00
d612c085f0
Add a message saying the bot is open-source 2024-09-22 23:15:27 -04:00
9e03210af4
Add configurable fallback locale as settings.fallbackLocale 2024-09-21 15:09:40 -04:00
a71121225c
Rename userSettingsDisabled to disableUserSettings 2024-09-21 14:58:34 -04:00
06cfc7347d
Update wording 2024-09-20 00:19:38 -04:00
b689f18627
/home/name3/Downloads/iwillfillupsystem/nw/mr/ringtones 2024-09-20 00:00:07 -04:00
a1c91568d3
Make the ad prefix self care better 2024-09-19 23:52:42 -04:00
223cd5a0aa
Lint 2024-09-19 23:27:19 -04:00
86275ef8ed
Add prefix selfcare 2024-09-19 23:27:00 -04:00
084eb15db8
Add ohio chat parser 2024-09-19 23:17:01 -04:00
307bbf15c2
Change order of args in playerdata event 2024-09-19 23:11:32 -04:00
02028f6a54
Add player data event 2024-09-19 23:05:54 -04:00
34075d8c86
Rename arguments to player plugin functions 2024-09-19 22:52:42 -04:00
dbba89fbe4
Make legacy chat support received UUIDs 2024-09-19 22:51:53 -04:00
4c04d06673
Remove extraneous chat types from subtypes 2024-09-19 22:47:29 -04:00
9d50d224ae
Make the chat parsers have priority levels to prevent running generic parsers first 2024-09-19 22:45:12 -04:00
24ce5d13fe
Lint 2024-09-19 22:21:01 -04:00
2ca476c0cc
Break the entire bot 2024-09-19 22:16:09 -04:00
8e7dd2bb4b
Bugfix 2024-09-19 22:12:30 -04:00
17e1576f68
Bugfix 2024-09-19 00:53:10 -04:00
d363bbc9f7
Bugfix 2024-09-19 00:50:02 -04:00
6245e8ef40
Seperate the chat parsers from the chat file & add message subtypes to the command class 2024-09-19 00:31:15 -04:00
0516ee1797
Remove Ohio debugger 2024-09-18 23:03:47 -04:00
97bf3d0d56
Rename !chat to chat 2024-09-18 23:02:35 -04:00
d98073b9da
Block settings command from loading when user settings are disabled 2024-09-18 03:32:18 -04:00
5aafb01b22
Change author 2024-09-18 03:07:59 -04:00
76bb172416
Update packages 2024-09-14 12:50:39 -04:00
24236cf7a7
Merge branch 'main' of code.chipmunk.land:7cc5c4f330d47060/owobot 2024-09-14 12:48:44 -04:00
fffa39abe8
Bump version 2024-09-14 12:48:13 -04:00
6cdec0db4d
Add IPv6 server display mode 2024-09-13 23:24:48 -04:00
3a6867ee96
Add hover and click event to help command 2024-09-13 04:11:54 -04:00
441418c8e7
Bugfix 2024-09-13 03:47:47 -04:00
cf75c34e7b
Merge branch 'main' of code.chipmunk.land:7cc5c4f330d47060/owobot 2024-09-13 03:31:21 -04:00
c461e87ef1
Add permission level to help 2024-09-13 03:30:34 -04:00
a4ff4ca374
Bugfix 2024-09-13 03:20:12 -04:00
b1d6b159ab
Make plain parse use forEach 2024-09-13 03:15:09 -04:00
8ed9d06121
Rename normal to public 2024-09-13 03:09:13 -04:00
e46a76e9f6
Remove console level from help command 2024-09-13 03:08:44 -04:00
7dea5a7355 Update package-lock.json 2024-09-12 01:53:29 -04:00
f9ffb00468 Update package.json 2024-09-12 01:52:37 -04:00
774204582e
update readme 2024-09-12 01:20:19 -04:00
97767b6aa5
Force chat for old MC versions 2024-09-12 01:18:23 -04:00
57e84ef53a
Change file permissions to 755 2024-09-12 00:53:24 -04:00
598723f7cc
Limit netmsg length to 512 2024-09-12 00:47:58 -04:00
54fd31f890
Change chat length based on version 2024-09-12 00:40:05 -04:00
e609a1b716
Bugfix 2024-09-12 00:37:46 -04:00
bfe1111e29
Lint 2024-09-12 00:26:36 -04:00
9847623b25
Add protocol version getter 2024-09-12 00:17:46 -04:00
a67785b1d7
Add protocol version getter 2024-09-12 00:17:09 -04:00
19e21b1594
Bugfix 2024-09-12 00:09:00 -04:00
a76971147e
Bugfix 2024-09-11 23:58:16 -04:00
bfd8c76e15
Bugfix 2024-09-11 23:57:32 -04:00
b8a6883933
Rename index.bot to index.bots 2024-09-11 23:44:17 -04:00
9c6eb5ee4e
Bugfix 2024-09-11 23:38:55 -04:00
284ebf488e
Add use chat mode 2024-09-11 23:38:34 -04:00
d6db8547a3
Update packages 2024-09-11 17:43:11 -04:00
270c7442c6
Bump version 2024-09-11 17:39:27 -04:00
cde624bbcf
Seperate permissions from command plugin; add command rewriter 2024-09-11 02:02:29 -04:00
316fcd1f86
Add message type to command logging 2024-09-11 01:36:42 -04:00
d23094ccfd
Command event overhaul 2024-09-11 01:35:15 -04:00
523bd90179
Fix the Git repo in version.json 2024-09-08 22:42:48 -04:00
43ed8beab8
Case sensitivity fixes 2024-09-08 22:20:14 -04:00
69b8f32266
Fix "info serveR 2024-09-08 22:14:44 -04:00
8d5e8a61a1
Improvements to about command 2024-09-08 22:12:53 -04:00
aaf56e4b92
Bugfix for "SERVERS 2024-09-08 22:09:43 -04:00
26534a28d3
Update branding
If it causes problems, botvX
2024-09-08 22:04:10 -04:00
7d141f1cc5
Update No permession message to include reference to proxies 2024-09-06 17:38:19 -04:00
ff722932bc
Update No permession message 2024-09-06 17:35:29 -04:00
21263ca4d2
Eval command overhaul 2024-09-06 17:31:33 -04:00
9928432592
Remove console permission level 2024-09-06 16:59:16 -04:00
464f1ac009
Remove strings related to console permission level 2024-09-06 16:57:27 -04:00
c23d6bd3f1
Make eval level 2 2024-09-06 16:56:33 -04:00
f7d0a17afc
Add uuid to hash 2024-09-06 16:55:01 -04:00
e243eb02f7
Add memory to serverinfo 2024-09-05 15:50:11 -04:00
946698b705
Add m_c_player format 2024-09-02 22:32:35 -04:00
b02f53d0c6
Add online mode 2024-09-02 16:41:07 -04:00
ea31b52917
Add chipmunk mod format 2024-09-02 15:52:27 -04:00
a93648958e
Change author 2024-08-30 21:42:49 -04:00
u0_a342
189f2a1f60 Update packages 2024-08-28 23:21:05 -04:00
413c77cf89 Readme fix 2024-08-28 23:08:00 -04:00
35ebfb4ef8
Add provisional branding which is subject to change 2024-08-28 20:10:52 -04:00
0c6605462f
README improvements 2024-08-27 08:43:56 -04:00
af05ff16e9 Merge branch 'main' of https://code.chipmunk.land/7cc5c4f330d47060/botvX 2024-08-26 22:32:29 -04:00
189c04d2d2
Lint 2024-08-25 22:29:39 -04:00
ae14106a0d
Add disable of incoming netmsg 2024-08-25 22:20:34 -04:00
f8ddba5fd7
Add anti-spam system 2024-08-25 22:13:46 -04:00
8a7a97cfe9
Allow bot owners to disable user settings 2024-08-25 21:53:03 -04:00
da1a55616d
Fix end portal bug with packets 2024-08-25 21:45:47 -04:00
945f3a8276
Hide hidden commands within specific command help 2024-08-25 21:33:32 -04:00
eb70a31db7
Remove settings location from example settings 2024-08-25 21:32:59 -04:00
ce13b085ec
Add comments 2024-08-09 02:59:45 -04:00
c074b030aa
Show version in "Operating system" item 2024-08-09 02:55:55 -04:00
b18f9a850a
Remove serverinfov9 2024-08-09 02:37:22 -04:00
1f24c53603
Finish serverinfovX 2024-08-09 02:34:17 -04:00
6d6119bc07
Bugfix (for real) 2024-08-09 01:53:50 -04:00
9050dfbe7f
Revert 2024-08-09 01:53:19 -04:00
ea54f228d4
Bugfix 2024-08-09 01:52:16 -04:00
d7101c1d4b
Remove version from about 2024-08-09 01:51:05 -04:00
cb39c0fb04
Add more of serverinfo's requires to the about command 2024-08-09 01:41:02 -04:00
e8ed4dd501
Add a beta of a new server info system 2024-08-09 01:37:50 -04:00
3a86ef8e5d
Seperate this function 2024-08-09 01:26:27 -04:00
4bafb14418
Remove/rename serverinfo translations in en-US language 2024-08-09 01:22:19 -04:00
2ca151b4b2
Remove server info translatins from uwu language 2024-08-09 01:19:33 -04:00
2881f1918a
Deprecate botv9 serverinfo command 2024-08-09 01:13:05 -04:00
a7263576bc
New commnet 2024-08-09 00:58:44 -04:00
c8df297f66
Remove server info from aboutcommand 2024-08-09 00:45:11 -04:00
951a3dad29
Increase cc_size selfcare 2024-08-08 11:39:58 -04:00
9aa49a28eb
Aliases translate 2024-08-08 03:10:05 -04:00
7d93eafd72
Change how strings work 2024-08-08 03:01:25 -04:00
af0b2405b4
Break aliases (I want to work on something else) 2024-08-08 02:55:28 -04:00
103a3790f7
Lint 2024-08-08 02:53:02 -04:00
0974696db2
Change the case of disconnect 2024-08-08 02:46:59 -04:00
b17409deea
Remove temu.com debugger 2024-08-08 02:46:20 -04:00
e5e27f38d4
Windows 7 build 7600.16384 (RTM Escrow) 2024-08-07 03:13:02 -04:00
035729a1db
Profileless chat bugfix 2024-08-07 03:10:48 -04:00
217804a5c6
Samsung Galaxy S7 Edge 2024-08-07 03:01:42 -04:00
57 changed files with 963 additions and 318 deletions

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 7cc5c4f330d47060
Copyright (c) 2024-2025 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

@ -1,28 +1,32 @@
# botvX
# owobot
## What is it?
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:
owobot 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)
- a self care system
- 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 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.
## How to install?
1. Install [Node.js](https://nodejs.org/) for your operating system.
2. Download the latest release, or alternatively, download the latest development version using <code>git clone https://code.chipmunk.land/7cc5c4f330d47060/botvX/</code>.
2. Download the latest release, or alternatively, download the latest development version using `git clone https://code.chipmunk.land/7cc5c4f330d47060/owobot`.
3. Extract the files if necessary.
4. Run <code>npm install</code> in the bot's directory. If it doesn't work, try using the Node.js command prompt, or adding Node.js to your PATH.
5. Copy <code>settings_example.json</code> to <code>settings.json</code> , and adjust the settings to fit your needs. Do not forget to also create a secrets file. An example secrets file is provided as <code>secret_example.json</code>. Do not forget, if you use the secrets template, to change the keys (the ones in there are public after all!).
6. Run ./launch.sh (macOS, Linux, FreeBSD) or ./launch.cmd (Windows) to start a bot launcher, which will reload the bot when the process closes. Alternatively, you can run <code>node index.js</code> to start the bot only once (it will still rejoin when kicked). If it displays an error saying Node is not a command, please make sure Node.js is on your PATH.
4. Run `npm install` in the bot's directory. If it doesn't work, try using the Node.js command prompt, or adding Node.js to your PATH.
5. Copy `settings_example.json` to `settings.json` and `secret_example.json` to `secret.json`, and adjust the settings to fit your needs. Change the example keys in secret.json as well.
6. Run ./launch.sh (macOS, Linux, FreeBSD) or ./launch.cmd (Windows). This will start a bot launcher, which will restart the bot when the process closes. Alternatively, you can run `node index.js` to start the bot only once (it will still rejoin when kicked). If it displays an error saying `node` is not a command, please make sure Node.js is on your PATH.
## Command list
| Name | Usage | Description |
|-|-|-|
| about | | About the bot |
| about | [serverlist \| servers \| server] | About the bot. May also show system information or a list of connected servers. |
| cb | \<command\> | Run a command in a command block |
| cloop | add <rate> <command>, remove <index>, list, clear | Manage command loops |
| eval | \<code\> | Run JavaScript code (must run through console)|
@ -30,10 +34,12 @@ botvX is a Minecraft bot originally designed for [Kaboom](https://kaboom.pw/) an
| logoff | | Disconnect and reconnect the bot from a server |
| netmsg | \<message\> | Send a message to all servers the bot is connected to |
| refill | | Refill core |
| restart | | Restart bot, closes when launched directly |
| say | \<message\> | Sends a message to chat |
| serverinfo | | Get system/bot info, similar to Kaboom's <code>serverinfo</code> command |
| stop | | Restart bot |
| settings | get, set <key> <value> | Set your user preferences |
| stop | | Close bot |
| template | | Used in development, does nothing |
| test | | Debug command for the chat parser |
| tpr | | Teleport to a random location |
| verify | | Check the hashing system |
| validate | | Check the hashing system |

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

@ -1,6 +1,7 @@
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')
@ -28,6 +29,10 @@ 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,
@ -155,6 +160,21 @@ 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})`
@ -201,10 +221,16 @@ const aboutServer = function (c) {
}
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
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
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,
@ -214,11 +240,11 @@ const displayServerList = function (c) {
color: c.colors.primary
},
{
text: `${item.host.host}:${item.host.port}`,
text: `${host}:${port}`,
color: c.colors.primary,
clickEvent: {
action: 'copy_to_clipboard',
value: `${item.host.host}:${item.host.port}`
value: `${host}:${port}`
},
hoverEvent: {
action: 'show_text',
@ -239,10 +265,11 @@ const displayServerList = function (c) {
module.exports = {
execute: function (c) {
let subcmd = c.args[0]
let subcmd
if (c.args.length >= 1) subcmd = c.args[0].toLowerCase()
if (subcmd === 'servers') subcmd = 'serverlist'
if (c.cmdName === 'serverinfo') subcmd = 'server'
if (c.cmdName === 'serverlist' || c.cmdName === 'servers') subcmd = 'serverlist'
if (c.cmdName.toLowerCase() === 'serverinfo' || c.cmdName.toLowerCase() === 'specs') subcmd = 'server'
if (c.cmdName.toLowerCase() === 'serverlist' || c.cmdName.toLowerCase() === 'servers') subcmd = 'serverlist'
if (subcmd === 'server') {
aboutServer(c)
} else if (subcmd === 'serverlist') {
@ -251,5 +278,5 @@ module.exports = {
aboutBot(c)
}
},
aliases: ['info', 'serverlist', 'servers', 'serverinfo']
aliases: ['info', 'serverlist', 'servers', 'serverinfo', 'specs']
}

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

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

@ -1,7 +1,8 @@
const { getMessage } = require('../util/lang.js')
module.exports = {
execute: (c) => {
const subcmd = c.args.splice(0, 1)[0]
let subcmd
if (c.args.length >= 1) subcmd = c.args.splice(0, 1)[0].toLowerCase()
switch (subcmd) {
case 'add': {
const rate = +(c.args.splice(0, 1)[0])

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

@ -1,11 +1,41 @@
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) => {
try {
console.log(eval(c.args.join(' ')))
} catch (e) {
console.error(e)
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
}
}
}
]
})
}
},
level: 3
level: 2
}

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

@ -1,10 +1,11 @@
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]].level ? cmds[c1.with[0]].level : 0
const level2 = cmds[c2.with[0]].level ? cmds[c2.with[0]].level : 0
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
return level1 - level2
}
@ -15,6 +16,7 @@ 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) {
@ -26,47 +28,120 @@ 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
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'
if (colorList[cmds[i].level]) {
cmdColor = colorList[cmds[i].level]
} else {
cmdColor = colorList[0]
}
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: [
i
{
text: i,
hoverEvent: {
action: 'show_text',
value: hoverText,
contents: hoverText
},
clickEvent: {
action: 'suggest_command',
value: `${c.prefix}${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: [
getMessage(c.lang, 'command.help.cmdList'),
{
translate: '%s (%s):',
with: [
getMessage(c.lang, 'command.help.cmdList'),
permListFormat
]
},
commandList.sort(sortHelp)
]
})
}
const printCmdHelp = (c) => {
const cmd = c.args[0]
if (!cmds[cmd]) {
let cmd
if (c.args.length >= 1) cmd = c.args[0].toLowerCase()
if (!cmds[cmd] || (cmds[cmd].hidden && c.type !== 'console')) {
c.reply({ text: getMessage(c.lang, 'command.help.noCommand') })
return
}
@ -118,14 +193,13 @@ 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, permsC][rPerms],
text: [permsN, permsT, permsO][rPerms],
color: c.colors.primary
}
]

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

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

@ -1,4 +1,4 @@
const { bot } = require('../index.js')
const { bots } = require('../index.js')
const { getMessage } = require('../util/lang.js')
module.exports = {
execute: (c) => {
@ -7,6 +7,8 @@ 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',
@ -41,12 +43,13 @@ module.exports = {
color: c.colors.primary
},
{
text: c.args.join(' ')
text: c.args.join(' ').slice(0, 512)
}
],
color: 'white'
}
bot.forEach(item => {
bots.forEach(item => {
if (item.host.options && item.host.options.netmsgIncomingDisabled && c.type !== 'console') return
item.tellraw('@a', json)
})
}

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

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

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

@ -1,7 +1,41 @@
const settings = require('../settings.json')
const version = require('../version.json')
module.exports = {
execute: (c) => {
if (c.args[0].startsWith('/') && c.verify < 1) return
c.bot.chat(c.args.join(' '))
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))
},
consoleIndex: true,
aliases: ['echo']

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

@ -1,5 +1,6 @@
const { languages, getMessage } = require('../util/lang.js')
const fs = require('fs')
const settings = require('../settings.json')
module.exports = {
execute: (c) => {
if (c.type === 'console') {
@ -9,7 +10,15 @@ module.exports = {
})
return
}
const subcmd = c.args.splice(0, 1)[0]
if (settings.disableUserSettings) {
c.reply({
text: getMessage(c.lang, 'command.settings.disabled.global'),
color: c.colors.secondary
})
return
}
let subcmd
if (c.args.length >= 1) subcmd = c.args.splice(0, 1)[0].toLowerCase()
switch (subcmd) {
case 'set':{
const allowedKeys = ['colorPrimary', 'colorSecondary', 'lang']

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

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

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

@ -37,6 +37,7 @@ 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 Normal file → Executable file
View file

@ -4,13 +4,12 @@ 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, permsC][c.verify],
text: [permsN, permsT, permsO][c.verify],
color: c.colors.primary
}
]

View file

@ -8,14 +8,18 @@ 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.')
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.')
}
const m = require('minecraft-protocol')
const generateUser = require('./util/usergen.js')
const EventEmitter = require('node:events')
const settings = require('./settings.json')
module.exports.bot = []
const secret = require('./secret.json')
const version = require('./version.json')
const protover = require('./util/getProtocolVersion.js')
const mcd = require('minecraft-data')
module.exports.bots = []
const botplug = []
const bpl = fs.readdirSync('plugins')
@ -32,44 +36,69 @@ const loadplug = (botno) => {
botplug.forEach((plug) => {
try {
if (plug.load) {
plug.load(module.exports.bot[botno])
plug.load(module.exports.bots[botno])
}
} catch (e) { console.log(e) }
})
}
let bypassWarningShown = false
const createBot = function createBot (host, oldId) {
if (host.options.disabled) {
return
}
const bot = new EventEmitter()
bot._client = m.createClient({
const options = {
host: host.host,
port: host.port ? host.port : 25565,
username: generateUser(host.options.legalName),
version: host.version ? host.version : settings.version_mc
})
if (typeof oldId !== 'undefined') {
for (const i in module.exports.bot[oldId].interval) {
clearInterval(module.exports.bot[oldId].interval[i])
}
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
}
delete module.exports.bot[oldId]
bot.id = oldId
module.exports.bot[oldId] = bot
}
if (host.options.online) {
options.username = secret.onlineEmail
options.password = secret.onlinePass
options.auth = 'microsoft'
} else {
bot.id = module.exports.bot.length
module.exports.bot.push(bot)
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])
}
delete module.exports.bots[oldId]
bot.id = oldId
module.exports.bots[oldId] = bot
} else {
bot.id = module.exports.bots.length
module.exports.bots.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, msg) => {
console.log(`[${bot.id}] [${type}] ${msg}`)
bot.displayChat = (type, subtype, msg) => {
if (settings.displaySubtypesToConsole) {
console.log(`[${bot.id}] [${type}] [${subtype}] ${msg}`)
} else {
console.log(`[${bot.id}] [${type}] ${msg}`)
}
}
loadplug(bot.id)

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

@ -11,6 +11,7 @@
"time.minutePlural": " minutes ",
"time.second": " second ",
"time.secondPlural": " seconds ",
"chat.antiSpamTriggered": "Anti-spam has been triggered for this server.",
"command.about.usage": "",
"command.about.desc": "About the bot",
"command.cb.usage": " <command>",
@ -31,20 +32,23 @@
"command.say.desc": "Sends a message to chat",
"command.settings.usage": " get|| set <key> <value>",
"command.settings.desc": "Set your user preferences",
"command.restart.usage": "",
"command.restart.desc": "Restart bot",
"command.stop.usage": "",
"command.stop.desc": "Restart bot",
"command.stop.desc": "Stop bot",
"command.template.usage": " <required> [optional]",
"command.template.desc": "Does nothing",
"command.test.usage": " [args...]",
"command.test.desc": "Chat parsing debugger command",
"command.tpr.usage": "",
"command.tpr.desc": "Teleport to a random location",
"command.verify.usage": " [args...]",
"command.verify.desc": "Check the hashing system",
"command.validate.usage": " [args...]",
"command.validate.desc": "Check the hashing system",
"command.about.author": "%s - a Minecraft bot made by %s for Kaboom and clones",
"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",
@ -52,15 +56,19 @@
"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.help.cmdList": "Commands:",
"command.eval.output": "Output",
"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.permsNormal": "Normal",
"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.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.",
@ -79,6 +87,7 @@
"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",
@ -97,6 +106,9 @@
"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",
@ -114,7 +126,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 your client's hashing system.",
"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.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": "botv10",
"version": "10.0.0",
"name": "botv11",
"version": "11.0.0-alpha.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "botv10",
"version": "10.0.0",
"name": "botv11",
"version": "11.0.0-alpha.2",
"license": "MIT",
"dependencies": {
"minecraft-protocol": "^1.45.0",
@ -14,21 +14,21 @@
}
},
"node_modules/@azure/msal-common": {
"version": "14.14.1",
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.14.1.tgz",
"integrity": "sha512-2Q3tqNz/PZLfSr8BvcHZVpRRfSn4MjGSqjj9J+HlBsmbf1Uu4P0WeXnemjTJwwx9KrmplsrN3UkZ/LPOR720rw==",
"version": "14.15.0",
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.15.0.tgz",
"integrity": "sha512-ImAQHxmpMneJ/4S8BRFhjt1MZ3bppmpRPYYNyzeQPeFN288YKbb8TmmISQEbtfkQ1BPASvYZU5doIZOPBAqENQ==",
"license": "MIT",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@azure/msal-node": {
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.13.0.tgz",
"integrity": "sha512-DhP97ycs7qlCVzzzWGzJiwAFyFj5okno74E4FUZ61oCLfKh4IxA1kxirqzrWuYZWpBe9HVPL6GA4NvmlEOBN5Q==",
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.15.0.tgz",
"integrity": "sha512-gVPW8YLz92ZeCibQH2QUw96odJoiM3k/ZPH3f2HxptozmH6+OnyyvKXo/Egg39HAM230akarQKHf0W74UHlh0Q==",
"license": "MIT",
"dependencies": {
"@azure/msal-common": "14.14.1",
"@azure/msal-common": "14.15.0",
"jsonwebtoken": "^9.0.0",
"uuid": "^8.3.0"
},
@ -37,18 +37,18 @@
}
},
"node_modules/@types/node": {
"version": "22.5.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz",
"integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==",
"version": "22.8.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.4.tgz",
"integrity": "sha512-SpNNxkftTJOPk0oN+y2bIqurEXHTA2AOZ3EJDDKeJ5VzkvvORSvmQXGQarcOzWV1ac7DCaPBEdMDxBsM+d8jWw==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
"undici-types": "~6.19.8"
}
},
"node_modules/@types/readable-stream": {
"version": "4.0.15",
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.15.tgz",
"integrity": "sha512-oAZ3kw+kJFkEqyh7xORZOku1YAKvsFTogRY8kVl4vHpEKiDkfnSA/My8haRE7fvmix5Zyy+1pwzOi7yycGLBJw==",
"version": "4.0.16",
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.16.tgz",
"integrity": "sha512-Fvp+8OcU8PyV90KTk5tR/rI8OjD3MP5NUow5rjOsZo+9zxf4p4soJtK9j4V6yeG30TH6rZxqRaP4JLa8lNNTNQ==",
"license": "MIT",
"dependencies": {
"@types/node": "*",
@ -189,12 +189,12 @@
"license": "MIT"
},
"node_modules/debug": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "2.1.2"
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@ -257,9 +257,9 @@
"license": "MIT"
},
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
@ -296,12 +296,6 @@
],
"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",
@ -427,9 +421,9 @@
"license": "MIT"
},
"node_modules/minecraft-data": {
"version": "3.68.0",
"resolved": "https://registry.npmjs.org/minecraft-data/-/minecraft-data-3.68.0.tgz",
"integrity": "sha512-pNBTi39a1zbFpN9itwi0YSL3hqAsSw38D7pE9C6m+aURmXljpBlNTO+TkpZxxDv4KqqtNBOhmkj4x46IDW6R+Q==",
"version": "3.78.0",
"resolved": "https://registry.npmjs.org/minecraft-data/-/minecraft-data-3.78.0.tgz",
"integrity": "sha512-Ssks8QD31lsoxqa7LySTqeP9romsfAbfsSGiUHiGMeqfxRi/PtOxGLyKD1BXB8V/tXLztFcbQYqzIhprDkPguw==",
"license": "MIT"
},
"node_modules/minecraft-folder-path": {
@ -439,9 +433,9 @@
"license": "MIT"
},
"node_modules/minecraft-protocol": {
"version": "1.47.0",
"resolved": "https://registry.npmjs.org/minecraft-protocol/-/minecraft-protocol-1.47.0.tgz",
"integrity": "sha512-IHL8faXLLIWv1O+2v2NgyKlooilu/OiSL9orI8Kqed/rZvVOrFPzs2PwMAYjpQX9gxLPhiSU19KqZ8CjfNuqhg==",
"version": "1.50.0",
"resolved": "https://registry.npmjs.org/minecraft-protocol/-/minecraft-protocol-1.50.0.tgz",
"integrity": "sha512-GiZy8g4YG0iZEKifX6ulCyhVnTDGZ1gH0ouUdxjo6xkKwp4KOf+ptbBgZ8G5+WHCumrI91+v/JYU07uCvKdi0w==",
"license": "BSD-3-Clause",
"dependencies": {
"@types/readable-stream": "^4.0.0",
@ -451,7 +445,7 @@
"endian-toggle": "^0.0.0",
"lodash.get": "^4.1.2",
"lodash.merge": "^4.3.0",
"minecraft-data": "^3.55.0",
"minecraft-data": "^3.78.0",
"minecraft-folder-path": "^1.2.0",
"node-fetch": "^2.6.1",
"node-rsa": "^0.4.2",
@ -459,7 +453,7 @@
"prismarine-chat": "^1.10.0",
"prismarine-nbt": "^2.5.0",
"prismarine-realms": "^1.2.0",
"protodef": "^1.8.0",
"protodef": "^1.17.0",
"readable-stream": "^4.1.0",
"uuid-1345": "^1.0.1",
"yggdrasil": "^1.4.0"
@ -484,9 +478,9 @@
"license": "BSD-3-Clause"
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/nearley": {
@ -586,12 +580,12 @@
}
},
"node_modules/prismarine-registry": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/prismarine-registry/-/prismarine-registry-1.7.0.tgz",
"integrity": "sha512-yyva0FpWI078nNeMhx8ekVza5uUTYhEv+C+ADu3wUQXiG8qhXkvrf0uzsnhTgZL8BLdsi2axgCEiKw9qSKIuxQ==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/prismarine-registry/-/prismarine-registry-1.10.0.tgz",
"integrity": "sha512-6TYQiZHtsJ87HsB2E0yamCFp77ZyyLT16OmW5iXB5V30yCPflhHvR5TR2IqISmmiRc2093BkHfiIhsOZaMatmQ==",
"license": "MIT",
"dependencies": {
"minecraft-data": "^3.0.0",
"minecraft-data": "^3.70.0",
"prismarine-nbt": "^2.0.0"
}
},
@ -605,15 +599,15 @@
}
},
"node_modules/protodef": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/protodef/-/protodef-1.15.0.tgz",
"integrity": "sha512-bZ2Omw8dT+DACjJHLrBWZlqN4MlT9g9oSpJDdkUAJOStUzgJp+Zn42FJfPUdwutUxjaxA0PftN0PDlNa2XbneA==",
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/protodef/-/protodef-1.17.0.tgz",
"integrity": "sha512-mnpNPV3xwu63u3NwZuXM1RCp979vjHxUGHzVrb6dxbvof5Fx+b8Rs0G0c3xtEuFDreGAMWS7VrlNkDUDBMsFWQ==",
"license": "MIT",
"dependencies": {
"lodash.get": "^4.4.2",
"lodash.reduce": "^4.6.0",
"protodef-validator": "^1.3.0",
"readable-stream": "^3.0.3"
"readable-stream": "^4.4.0"
},
"engines": {
"node": ">=14"
@ -631,20 +625,6 @@
"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",
@ -776,12 +756,6 @@
"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": "botv10",
"version": "10.0.0",
"name": "botv11",
"version": "11.0.0-alpha.2",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"

View file

@ -2,6 +2,8 @@ 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) {
@ -24,8 +26,29 @@ const convertChatTypeItem = (item) => {
}
}
}
// 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']) {
@ -37,7 +60,8 @@ module.exports = {
}
})
b._client.on('profileless_chat', (data) => {
const messageType = b.messageTypes[data.type]
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') {
@ -51,37 +75,24 @@ module.exports = {
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', {
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
username,
playerChatType: messageType
})
})
b._client.on('player_chat', (data) => {
const messageType = b.messageTypes[data.type]
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') {
@ -99,85 +110,85 @@ module.exports = {
for (const i in messageType.style) {
json[i] = messageType.style[i]
}
b.emit('chat', {
b.emit('chat_unparsed', {
json,
type: 'player',
uuid: data.senderUuid,
message: data.plainMessage,
nickname: parsePlain(parse1204(data.networkName)),
username: b.findRealNameFromUUID(data.senderUuid)
username: b.findRealNameFromUUID(data.senderUuid),
playerChatType: messageType
})
})
b._client.on('system_chat', (data) => {
const json = parse1204(data.content)
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', {
b.emit('chat_unparsed', {
json,
type: 'system',
uuid,
message: split.join(': '),
nickname,
username
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)
const parsed = parsePlain(json)
let chatName
let nickname
let username
let message
let uuid
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', {
b.emit('chat_unparsed', {
json,
type: 'legacy',
uuid,
message,
nickname,
username
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)
b.displayChat(data.type, `${msgConsole}\x1b[0m`)
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.emit('plainchat', msgPlain, data.type, data.subtype)
b.displayChat(data.type, data.subtype, `${msgConsole}\x1b[0m`)
})
}
}

47
plugins/chatParsers/chat_cmm.js Executable file
View file

@ -0,0 +1,47 @@
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

@ -0,0 +1,27 @@
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

@ -0,0 +1,31 @@
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

@ -0,0 +1,20 @@
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

@ -0,0 +1,40 @@
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

@ -0,0 +1,33 @@
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', (name, uuid, text) => {
if (!settings.disableLogging && !settings.disableCommandLogging) chatlog(`cmd_${b.host.host}_${b.host.port}`, `${name} (${uuid}): ${text}`)
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}`)
})
}
}

View file

@ -1,51 +1,48 @@
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')) fs.mkdirSync('userPref')
if (!fs.readdirSync('.').includes('userPref') && !settings.disableUserSettings) fs.mkdirSync('userPref')
const loadSettings = function (uuid) {
try {
return require(`../userPref/${uuid}.json`)
if (settings.disableUserSettings) {
return {}
} else {
return require(`../userPref/${uuid}.json`)
}
} catch (e) {
return {}
}
}
module.exports = {
load: (b) => {
b.prefix = settings.prefix
b.lastCmd = 0
b.runCommand = (name, nickname, uuid, text, msgType, prefix) => {
b.on('chat', (data) => {
const fullCommand = data.message
for (const prefix of settings.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 = (name, nickname, uuid, text, msgType, msgSubtype, 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 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
}
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()]) {
try {
cmds[cmd[0].toLowerCase()].execute(new Command(uuid, name, nickname, text, msgType, prefix, b, verify, userSettings))
cmds[commandClass.cmdName.toLowerCase()].execute(commandClass)
} catch (e) {
console.log(e)
b.tellraw(uuid, {

View file

@ -1,4 +1,6 @@
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,
@ -17,6 +19,7 @@ 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: '/',
@ -63,18 +66,20 @@ module.exports = {
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.chat(b.refillCoreCmd)
}, true)
b.add_sc_task('cc_size', () => {
b.chat('/gamerule commandModificationBlockLimit 32768')
})
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.on('ccstart', () => {
setTimeout(() => { b.interval.ccqi = setInterval(b.advanceccq, 2) }, 1000)
b.ccStarted = true
})
b.on('chat', (data) => {
b.on('chat_unparsed', (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) {
@ -107,20 +112,28 @@ module.exports = {
b.tellraw = (uuid, message) => {
let finalname = ''
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)}]}]`
if (b.host.options.useChat) {
if (b.host.options.useAmpersandColorCodes) {
b.chat(mcParser(message).replaceAll('§', '&'))
} else {
b.chat(plainParser(message))
}
} else {
finalname = uuid
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)}`)
}
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 Normal file → Executable file
View file

@ -2,6 +2,7 @@ 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,
@ -14,7 +15,7 @@ rl.on('line', (l) => {
const tmpcmd = l.split(' ')
const index2 = tmpcmd.splice(1, 1)[0]
if (index2 === '*') {
for (let i = 0; i < index.bot.length; i++) {
for (let i = 0; i < index.bots.length; i++) {
const cmd = new ConsoleCommand(tmpcmd.join(' '), i)
cmds[l.split(' ')[0].toLowerCase()].execute(cmd)
}
@ -45,8 +46,12 @@ module.exports = {
b.info = (msg) => {
consoleWrite(`[${b.id}] [info] ${msg}`)
}
b.displayChat = (type, msg) => {
consoleWrite(`[${b.id}] [${type}] ${msg}`)
b.displayChat = (type, subtype, msg) => {
if (settings.displaySubtypesToConsole) {
consoleWrite(`[${b.id}] [${type}] [${subtype}] ${msg}`)
} else {
consoleWrite(`[${b.id}] [${type}] ${msg}`)
}
}
}
}

View file

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

31
plugins/perms.js Executable file
View file

@ -0,0 +1,31 @@
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 Normal file → Executable file
View file

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

View file

@ -1,3 +1,7 @@
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) {
/*
@ -12,17 +16,19 @@ module.exports = {
load: (b) => {
b.sc_tasks = {}
b.selfcareRun = 0
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()
b._client.on('login', () => {
b.interval.sc = setInterval(() => {
if (Date.now() - b.selfcareRun <= 600) {
return
}
}
b.selfcareRun = Date.now()
}, 40)
for (const i in b.sc_tasks) {
if (b.sc_tasks[i].failed) {
b.sc_tasks[i].failTask()
b.selfcareRun = Date.now()
}
}
}, 40)
})
b.add_sc_task = (name, failTask, startFailed) => {
b.sc_tasks[name] = new SCTask(failTask, startFailed)
}
@ -58,7 +64,7 @@ module.exports = {
})
}
// Gamemode
// Gamemode / end portal bug
b.add_sc_task('gamemode', () => {
b.chat('/minecraft:gamemode creative')
})
@ -67,6 +73,8 @@ module.exports = {
b.sc_tasks.gamemode.failed = 1
} else if (p.reason === 3 && p.gameMode === 1) {
b.sc_tasks.gamemode.failed = 0
} else if (p.reason === 4) {
b.sc_tasks.respawn.failed = 1
}
})
@ -75,11 +83,53 @@ module.exports = {
b._client.write('client_command', { actionId: 0 }) // Simulates respawning
b.sc_tasks.respawn.failed = 0
})
b.on('chat', (data) => {
b.on('chat_unparsed', (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 Normal file → Executable file
View file

View file

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

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

@ -1,6 +1,6 @@
const settings = require('../settings.json')
class Command {
constructor (uuid, user, nick, cmd, msgType, prefix, bot, verify, prefs) {
constructor (uuid, user, nick, cmd, msgType, msgSubtype, prefix, bot, prefs) {
this.send = (text, uuid) => { bot.tellraw(uuid || '@a', text) }
this.reply = text => bot.tellraw(uuid, text)
this.uuid = uuid
@ -8,16 +8,18 @@ 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 = verify
this.verify = 0
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 {
@ -36,6 +38,12 @@ 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]
}
}
}

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

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

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

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

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

98
util/chatparse_mc_withHex.js Executable file
View file

@ -0,0 +1,98 @@
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 Normal file → Executable file
View file

@ -29,10 +29,12 @@ const parse = function (_data, l = 0) {
if (lang[trans] !== undefined) {
trans = lang[trans].replace(/%%/g, '\ue123')
}
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'))
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'))
})
}
out += trans.replaceAll('\ud900\ud801', '%').replaceAll('\ud900\ud804', '%s').replaceAll('\ud900\ud805', '$s')
}

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

@ -1,4 +1,5 @@
const fs = require('fs')
const settings = require('../settings.json')
const cmds = Object.create(null)
const bpl = fs.readdirSync('./commands')
for (const plugin of bpl) {
@ -7,6 +8,7 @@ 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

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

4
util/getProtocolVersion.js Executable file
View file

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

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

@ -1,11 +1,11 @@
const crypto = require('crypto')
const secret = require('../secret.json')
module.exports = function (cmd) {
module.exports = function (cmd, uuid) {
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}:${cmdWithoutHash}:${dateString}`
const hashOwner = `babyboom:${secret.keyOwner}:${cmdWithoutHash}:${dateString}`
const hashTrusted = `babyboom:${secret.keyTrusted}:${uuid}:${cmdWithoutHash}:${dateString}`
const hashOwner = `babyboom:${secret.keyOwner}:${uuid}:${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 Normal file → Executable file
View file

@ -1,5 +1,7 @@
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')
@ -18,8 +20,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['en-US'] && languages['en-US'][message] !== undefined) {
message = languages['en-US'][message].replace(/%%/g, '\ue123')
} else if (languages[fallbackLocale] && languages['en-US'][message] !== undefined) {
message = languages[fallbackLocale][message].replace(/%%/g, '\ue123')
}
if (with2) {
with2.forEach((withItem, i) => {

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

15
util/memoryconvert.js Executable file
View file

@ -0,0 +1,15 @@
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 Normal file → Executable file
View file

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

@ -2,20 +2,17 @@ const crypto = require('crypto')
const rsg = function (count) {
let output = ''
for (let i = 0; i < count; i++) {
const type = Math.floor(Math.random() * 6)
const type = Math.floor(Math.random() * 5)
switch (type) {
case 0:
output += ' '
break
case 1:
output += '§§'
break
case 2:
case 1:
output += '§ '
break
case 2:
case 3:
case 4:
case 5:{ // Make this case more likely
case 4:{ // 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 Normal file → Executable file
View file

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

11
version.json Normal file → Executable file
View file

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