v6.0.0-alpha

This commit is contained in:
Parker2991 2024-07-07 15:44:16 -04:00
commit 2d49c8003f
47 changed files with 3894 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
node_modules
config.yml
.git
src/modules/exploits.js

80
Changelog.md Normal file
View file

@ -0,0 +1,80 @@
beta 0.1 - 0.2 0.5 release 2022 (first release)
ParkerBot/DEMONBOT/Woomybot/Boyfriend
ehh nothing much just the release of the betas
--------------------------------------
beta 1.0 release 1/25/23 codename: in console test.
original commands:!cloop bcraw,!cloop sudo,!troll,!say,!op (broke),!deop (broke), !gms (broke),!freeze,!icu <--- these commands no longer can be used in game but in console for beta 1.0
commands added: fake kick,ban,kick,crashserver,stop,gmc,greetin,test(broken idk),bypass,entity spam(broken idk),gms(broke),stop,tntspam (broke idk),prefix (not tested yet),annoy (broke results in a complete server crash keeping ayunboom down for 3 to 5 hours),freeze(i dont even know what this do since i cant do !freeze),crashserver,troll(more destructive),trol(more destructive),icu(broke idk),say,sudo,cloop
-------------------------------------
1.0 release 1/26/23 1:47am codename:
FNFBoyfriendBot.
commands added: BOOM,deop,troll and trol(added extra code to both commands),kaboom,serverdeop,
commands fixed:tp,gms,annoy(attemps to crash the server but not as bad as it was)
commands untested:prefix
command Broke:icu,freeze,tntspam,entityspam,tntspam?
changed name to &b &lFNFBoyfriendBot may change later idk
-------------------------------------
1.0 revision 1 release 1/26/23 2:00pm
codename revision 1.
reworked the kaboom command and fixed the description commands but thats about it. also reworked the greeting command
--------------------------------------
1.1 release 1/28/23 1:51
nothing much just added extra stuff to the troll, trol and that is about it
-------------------------------------
1.2 release 1/30/32 no codename
for ppl me making me really mad -.- got released early
--------------------------------------
2.0 2/07/23 8:01pm codename: Major
added DREAMSTANALERT,technoblade,GODSWORD,KFC,MYLEG,OHHAIL,altcrash,MyHead
Reworked tntspam,entityspam,soundbreaker
added Spim to the whitelist of the bot
released too early than it was planned gonna be released due do the code almost leaked it had to be released early
--------------------------------------
2.1 release 2/11/23 5:30pm
added: refillcore(had early prototypes of this was original), vanish,deop,cloopdeop,mute,cloopmute
reworked: op (supposed to already op the bot but didnt work until this release) and reworked gmc (same problem with op)
(had early prototypes of vanish,refillcore,gmc,and op but these were original gonna be automatic but after alot of attempts i said screw it and added 2 commands refillcore, and vanish reworked gmc and op and got them working finally) removed Spim because come to find out he couldnt be trusted
--------------------------------------
2.2 release 2/20/23 4:21pm central time
bug fixes
added ckill(added back after trial and error),serversuicidal
changed username of the bot from hex code to FNFBoyfriendBot because hex code for the username was confusing as it changes everytime
---------------------------------------
3.0 Beta codename: blue-balled corruption
was canceled due to ayunboom being rewriten and renamed to creayun barely usable on there because commands blocks are disabled which i created a bot for that server that has no command blocks https://replit.com/@Parker2991/FNFBoyfriendbotcreayun-bot-final-build#index.js just finished the final build of that bot due to chip announcing that he may make a kaboom clone yk what 1.5.2 and 1.8 support but anyway onto what is in the 3.0 beta well the beta for right now
commands added:discord,version,online,list,iownyou,endmysuffering,wafflehouse,whopper,bcraw,destroycore
Notes:the original say command was reworked into talking in chat without bcraw and command blocks which the bcraw chatting code is still in the bot but was reworked into the bcraw commmand. maybe some commands removed? i dont know yet edit there is 2 commands removed
commands removed:tpe and serverdeop???
reworked commands :say command for right now
relay chat mabe will be added as a seperate repl i dont know yet possible would need a whole code rewrite for relay chat
-----------------------------------------
3.0 full release CodeName:Sky Remanifested
the full release of 3.0 the rewrite has been pushed back to 4.0 due to 3.0 already pass its release date and the code i had on hand was done but the rewrite wasnt done
Added: SelfCare
Made during development:Relay chat prototypes for several servers
---------------------
3.0.5 release
Bug fixes
-----------
3.0.9
commands added:Help(finally added after about a year),consolelog(added cuz yes),cloopconsolelog(added cuz yes)
-------------------
4.0 beta Codename:FNFBoyfriendBot Ultimate
all of the command removed and or rewriten from version 3.0.9
Commands added or rewriten:ban,buyrealminecraft,cloop,discord,echo,errortest,freeze,help,icu,info,kick,bots,skids,romncitrash,say,selfdestruct,serversuicidal,sudo,test,trol,troll
(note that this is different and is not CommandModules)Modules Added:discord,chat,chat_command_handler,command_manager,position,registry,reconnect,command_core
CustomChats added:kaboom(for normal chat)
(note that this is different and is not Modules)CommandModules Added:command_error,Command_source
a beta release for rn
-----------------------------
4.0 Alpha Codename:FNFBoyfriendBot Ulitmate
Commands added: calculator,ckill,evaljs,urban,crash,cloopcrash,core,list,ping,netmsg,skin,tpr
Commands Removed:Buyrealminecraft
(note that this is different and is not CommandModules)Modules Added:op selfcare,gmc selfcare,vanish selfcare,cspy selfcare,console
(note that this is different and is not Modules)CustomChats Added:u2O3a(for custom chat)
added util with between(for urban) eval_colors(for evaljs)
----------------------------------

0
README.md Normal file
View file

1960
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

13
package.json Normal file
View file

@ -0,0 +1,13 @@
{
"dependencies": {
"discord.js": "^14.11.0",
"js-yaml": "^4.1.0",
"jvm": "^0.5.3",
"man-db": "^1.0.3",
"minecraft-data": "^3.36.1",
"minecraft-protocol": "^1.47.0",
"prismarine-auth": "^2.2.0",
"prismarine-chat": "^1.10.1",
"prismarine-registry": "^1.7.0"
}
}

74
src/bot.js Normal file
View file

@ -0,0 +1,74 @@
const mc = require('minecraft-protocol')
const { EventEmitter } = require('events')
const fs = require('fs')
const path = require('path')
require("events").EventEmitter.defaultMaxListeners = Infinity;
function createBot(options = {}) {
const bot = new EventEmitter()
bot.options = {
// Set some default values in options
host: options.host ??= 'localhost',
username: options.username ??= 'Player',
hideErrors: options.hideErrors ??= true, // HACK: Hide errors by default as a lazy fix to console being spammed with them
};
bot.options = options
// Create our client object, put it on the bot, and register some events
bot.on('init_client', client => {
client.on('packet', (data, meta) => {
bot.emit('packet', data, meta)
bot.emit('packet.' + meta.name, data)
})
client.on('login', () => {
bot.uuid = client.uuid
bot.username = client.username
})
client.on('disconnect', (data) => {
bot.emit("disconnect", data.reason)
})
client.on('end', reason => {
bot.emit('end', reason);
})
client.on('error', error => {
// bot.emit('error', error)
console.log(error.toString())
})
client.on("keep_alive", ({ keepAliveId }) => {
bot.emit("keep_alive", { keepAliveId })
})
client.on('kick_disconnect', (data) => {
bot.emit("kick_disconnect", data.reason)
})
process.on("uncaughtException", (e) => {
console?.warn(e.stack)
});
})
const client = options.client ?? mc.createClient(options)
bot._client = client
bot.emit('init_client', client)
bot.bots = options.bots ?? [bot]
// Modules
/*
bot.loadModule = module => module(bot, options)
for (const filename of fs.readdirSync(path.join(__dirname, 'modules'))) {
try {
const module = require(path.join(__dirname, 'modules', filename))
bot.loadModule(module)
} catch (error) {
console.error('Failed to load module', filename, ':', error)
}
}
*/
return bot
}
module.exports = createBot

199
src/commands/bots.js Normal file
View file

@ -0,0 +1,199 @@
// TODO: Maybe add more authors
const bots = [
{
name: { text: 'HBot', color: 'aqua', bold:true },
authors: ['hhhzzzsss'],
exclaimer:'HBOT HARRYBUTT LMAOOOOOOOOOOOOOOOOO',
foundation: 'java/mcprotocollib',
prefixes: ['#']
},
{
name: [{ text: 'Evil', color: 'dark_red' }, {text:'Bot', color:'dark_purple'}],
authors: ['FusseligerDev'],
exclaimer:'',
foundation: 'Java/Custom',
prefixes: ['!']
},
{
name: { text: 'SBot Java', color: 'white', bold:true }, // TODO: Gradient
authors: ['evkc'],
foundation: 'Java/MCProtocolLib',
prefixes: [':']
},
{
name: { text: 'SBot Rust', color: 'white', bold:true }, // TODO: Gradient
authors: ['evkc'],
foundation: 'Rust',
prefixes: ['re:']
},
{
name: { text: 'Z-Boy-Bot', color: 'dark_purple' }, // TODO: Gradient
exclaimer: 'Most likely skidded along with kbot that the dev used',
authors: ['Romnci'],
foundation: 'NodeJS/mineflayer or Java/mcprotocollib idfk',
prefixes: ['Z]']
},
{
name: { text: 'ABot', color: 'gold', bold:true }, // TODO: Gradient
exclaimer: '',
authors: ['yfd'],
foundation: 'NodeJS/Node-Minecraft-Protocol',
prefixes: ['<']
},
{
name: { text: 'FardBot', color: 'dark_purple' },
authors: ['_yfd'],
exclaimer: 'bot is dead lol',
foundation: 'NodeJS/Mineflayer',
prefixes: ['<']
},
{
name: { text: 'ChipmunkBot', color: 'green' },
authors: ['_ChipMC_'],
exclaimer: 'chips? also shoutout to chip and chayapak for helping in the rewrite',
foundation: 'Java/MCProtocolLib',
prefixes: ["'", "/'"]
},
{
name: { text: 'ChipmunkBot Old', color: 'green' },
authors: ['_ChipMC_'],
foundation: 'NodeJS/Node-Minecraft-Protocol',
},
{
name: { text: 'TestBot', color: 'aqua' },
authors: ['Blackilykat'],
foundation: 'Java/MCProtocolLib',
prefixes: ["-"]
},
{
name: { text: 'UBot', color: 'grey' },
authors: ['HexWoman'],
exclaimer: 'UwU OwO',
foundation: 'NodeJS/node-minecraft-protocol',
prefixes: ['"']
},
{
name: { text: 'ChomeNS Bot Java', color: 'yellow'},
authors: ['chayapak'],
exclaimer: 'wow its my bot !! ! 4374621q43567%^&#%67868-- chayapak',
foundation: 'Java/MCProtocolLib',
prefixes: ['*', 'cbot ', '/cbot ']
},
{
name: { text: 'ChomeNS Bot NodeJS', color: 'yellow'},
authors: ['chayapak'],
foundation: 'NodeJS/Node-Minecraft-Protocol',
prefixes: ['*', 'cbot', '/cbot']
},
{
name: { text: 'RecycleBot', color: 'dark_green'},
foundation: ['MorganAnkan'],
exclaimer: 'nice bot',
language: 'NodeJS/node-minecraft-protocol',
prefixes: ['=']
},
{
name: { text: 'ManBot', color: 'dark_green' , },
exclaimer: '(more like men bot :skull:) OH HAAAAAAAAAAAAAAIIILL LOGINTIMEDOUT',
authors: ['Man/LogintimedOut'],
foundation: 'NodeJS/mineflayer',
prefixes: ['(Note:I dont remember!!)']
},
{
name: [{ text: 'Useless', color: 'red', bold:false}, { text: 'Bot', color: 'gray', bold:false}],
exclaimer: 'it isnt useless its a good bot................',
authors: ['IuCC'],
foundation: 'NodeJS/node-minecraft-protocol',
prefixes: ['[']
},
{
name: [{ text: 'Blurry', color: 'dark_purple'}, { text: 'Bot', color: 'red' }],
exclaimer: '',
authors: ['SirLennox'],
foundation: 'Java/custom',
prefixes: [',']
},
{
name: [{ text: 'KittyCorp', color: 'yellow' }, { text: 'Bot', color: 'yellow' }],
exclaimer: '3 words ginlang is gay',
authors: ['ginlang , G6_, ArrayBuffer, and i guess more??'],
foundation: 'NodeJS/node-minecraft-protocol',
prefixes: ['^']
},
{
name: [{ text:'FNF', color: 'dark_purple', bold: true}, {text:'Boyfriend', color: 'aqua', bold:true}, {text:'Bot', color:'dark_red', bold:true}, {text:'X', color:'black', bold:true}],
authors: [{ text:'Parker2991', color: 'dark_red'}, {text:' _ChipMC_', color: 'dark_green', bold:true}, {text:' chayapak', color:'yellow', bold:true}],
exclaimer: '4.0 (this Bot) also the Ultimate version of the FNFBoyfriendBot Builds',
foundation: 'NodeJS/node-minecraft-protocol',
prefixes: ['~']
},
{
name: [{ text:'FNF', color: 'dark_purple', bold: true}, {text:'Boyfriend', color: 'aqua', bold:true}, {text:'Bot', color:'dark_red', bold:true}, {text:' Legacy', color:'green', bold:true}],
authors: [{text:'Parker2991', color:'dark_red' }, {text:' _ChipMC_', color:'dark_green', bold:true }],
exclaimer:'1037 LINES OF CODE WTFARD!??! also this version is in console commands only' ,
foundation: 'NodeJS/mineflayer',
prefixes: []
}
]
module.exports = {
name: 'bots',
trustLevel: 0,
aliases: [
"knownbots"
],
description: 'A list of known bots',
usages: [
'<bot>',
],
execute (context) {
const query = context.arguments.join(' ').toLowerCase()
const source = context.source;
const bot = context.bot;
if (query.length === 0) {
const list = []
for (const info of bots) {
if (list.length !== 0) list.push({ text: ', ', color: 'gray' })
list.push(info.name)
}
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, ['Known bots (', bots.length, ') - ', ...list], false)
return
}
for (const info of bots) {
const plainName = String(context.bot.getMessageAsPrismarine(info.name)).toLowerCase()
if (plainName.includes(query)) this.sendBotInfo(info, context.bot)
}
},
sendBotInfo (info, bot) {
const component = ['']
component.push('Name: ', info.name)
if (info.exclaimer) component.push('\n', 'Exclaimer: ', info.exclaimer)
if (info.authors && info.authors.length !== 0) {
component.push('\n', 'Authors: ')
for (const author of info.authors) {
component.push(author, { text: ', ', color: 'gray' })
}
component.pop()
}
if (info.foundation) component.push('\n', 'Foundation: ', info.foundation)
if (info.prefixes && info.prefixes.length !== 0) {
component.push('\n', 'Prefixes: ')
for (const prefix of info.prefixes) {
component.push(prefix, { text: ', ', color: 'gray' })
}
component.pop()
}
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, [component])
}
}//it doing it just for the ones i added lol
// prob a replit moment, it probably thinks there are regexes in the strings

77
src/commands/cloop.js Normal file
View file

@ -0,0 +1,77 @@
module.exports = {
name: 'cloop',
trustLevel: 1,
aliases: [
"commandloop"
],
description: 'run cloops',
execute (context) {
const args = context.arguments
const bot = context.bot
const source = context.source
if (!args && !args[0] && !args[1] && !args[2] && !args[3]) return
switch (args[1]) {
case 'add':
if (parseInt(args[2]) === NaN) bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, { text: 'Invalid interval', color: 'red' })
const interval = parseInt(args[2])
const command = args.slice(3).join(' ');
bot.cloop.add(command, interval)
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, {
translate: 'Added \'%s\' with interval %s to the cloops',
with: [ command, interval ]
})
break
case 'remove':
if (parseInt(args[2]) === NaN) bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, { text: 'Invalid index', color: 'red' })
const index = parseInt(args[2])
bot.cloop.remove(index)
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, {
translate: 'Removed cloop %s',
with: [ index ]
})
break
case 'clear':
bot.cloop.clear()
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, { text: 'Cleared all cloops' })
break
case 'list':
const component = []
const listComponent = []
let i = 0
for (const cloop of bot.cloop.list) {
listComponent.push({
translate: '%s \u203a %s (%s)',
with: [
i,
cloop.command,
cloop.interval
]
})
listComponent.push('\n')
i++
}
listComponent.pop()
component.push({
translate: 'Cloops (%s):',
with: [ bot.cloop.list.length ]
})
component.push('\n')
component.push(listComponent)
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, component)
break
default:
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, { text: 'Invalid action', color: 'red' })
break
}
}
}

33
src/commands/console.js Normal file
View file

@ -0,0 +1,33 @@
module.exports = {
name: 'console',
trustLevel: 3,
aliases: [
],
execute (context) {
const bot = context.bot
const args = context.arguments;
const source = context.source;
if (!args && !args[0] && !args[1] && !args[2] && !args[3]) return;
switch (args[0]) {
case "consoleserver":
case "csvr":
const servers = bot.bots.map(eachBot => eachBot.options.host);
for (const eachBot of bot.bots) {
if (args.slice(1).join(' ').toLowerCase() === 'all') {
eachBot.console.consoleServer = 'all'
bot.console.log("Set the console server to all");
continue
}
const server = servers.find(server => server.toLowerCase().includes(args[1]))
if (!server) {
bot.console.log("Invalid server");
return
}
bot.console.log(`Set the console server to ` + server);
eachBot.console.consoleServer = server;
}
break
}
}
}

21
src/commands/core.js Normal file
View file

@ -0,0 +1,21 @@
const CommandError = require('../util/command_error')
module.exports = {
name: 'core',
trustLevel: 0,
aliases: [
"cb",
"corerun",
"commandcorerun",
],
description: 'run commands in core!',
execute (context) {
const bot = context.bot
const message = context.arguments.join(' ')
if (message.startsWith('/')) {
bot.core.run(message.substring(1))
return
}
bot.core.run(message)
}
}

9
src/commands/discord.js Normal file
View file

@ -0,0 +1,9 @@
const CommandError = require('../util/command_error')
module.exports = {
name: 'discord',
trustLevel: 0,
execute (context) {
bot.tellraw(context.bot.discord.invite, false)
}
}

19
src/commands/echo.js Normal file
View file

@ -0,0 +1,19 @@
module.exports = {
name: 'echo',
trustLevel: 0,
aliases: [
"say",
"botsay",
],
description: 'Make me say something',
execute (context) {
const bot = context.bot
const message = context.arguments.join(' ')
if (message.startsWith('/')) {
bot.chat.command(message.substring(1))
return
}
bot.chat.message(message)
}
}

10
src/commands/errortest.js Normal file
View file

@ -0,0 +1,10 @@
const CommandError = require('../util/command_error')
module.exports = {
name: 'errortest',
trustLevel: 0,
execute (context) {
const message = context.arguments.join(' ')
throw new Error(message)
}
}

93
src/commands/help.js Normal file
View file

@ -0,0 +1,93 @@
const CommandError = require('../util/command_error')
/*
pub_lickColor: "#2b7589"
t_rustedColor: "#219696"
own_herColor: "#2081c3"
*/
module.exports = {
name: 'help',
trustLevel: 0,
aliases: [
"heko",
"?",
"cmds",
],
description: 'a list of the bots commands',
execute (context) {
const commandList = [];
const bot = context.bot;
const source = context.source;
const args = context.arguments;
const selector = '@a';
console.log(source)
const category = {
translate: '(%s%s%s%s%s) \u203a ',
bold: false,
color: 'gray',
with: [
{ color: "blue", text: 'Public'},
{ color: "gray", text: ' | '},
{ color: "dark_aqua", text: 'Trusted'},
{ color: 'gray', text: ' | '},
{ color: "dark_blue", text: 'Owner'},
]
}
let public = [];
let trusted = [];
let owner = [];
for (const command of bot.commandManager.commandlist) {
console.log(command.name)
if (args[0] === command.name) {
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, [
{
text: `CommandName \u203a ${command.name}\n`,
color: 'gray',
},
{
text: `Aliases \u203a ${command.aliases}\n`,
color: 'gray',
},
{
text: `Description \u203a ${command.description}`,
color: 'gray',
}
]);
return
}
if (command.trustLevel === 0) {
public.push([
{
text: command.name + ' ',
color: "blue",
}
])
} else if (command.trustLevel === 1) {
trusted.push([
{
text: command.name + ' ',
color: "dark_aqua"
}
])
} else if (command.trustLevel === 2) {
owner.push([
{
text: command.name + ' ',
color: "dark_blue"
}
])
}
}
const length = bot.commandManager.commandlist.filter(c => c.trustLevel != 3).length
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, [
{ text: 'Commands (', color: 'gray' },
{ text: JSON.stringify(length), color: 'gold' },
{ text: ') ', color: 'gray' },
category,
public,
trusted,
owner
])
// bot.tellraw([ public, trusted, owner ])
}
}

35
src/commands/info.js Normal file
View file

@ -0,0 +1,35 @@
module.exports = {
name: 'info',
trustLevel: 0,
aliases: [
"information",
],
description: 'check the bots info',
execute (context) {
const bot = context.bot;
const args = context.arguments;
const config = context.config;
const discordClient = context.discordClient;
const source = context.source;
switch (args[0]) {
case 'version':
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, `§9Friday §9Night §9Funkin §3Boyfriend §1Bot§8§r-v6.0.0-alpha-700-§bSk§4y §bRedux\n11/22/22 - ${new Date().toLocaleDateString("en-US", { timeZone: "America/CHICAGO" })}`);
break // &9 &3 &1
case 'login':
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, [
{
text: `Minecraft username \u203a ${bot.options.username}\n`,
color: 'gray',
},
{
text: `Discord username \u203a ${discordClient.user.tag}`,
color: 'gray',
}
]);
break;
case 'discord':
bot.tellraw('@a', config.discord.invite)
break
}
}
}

51
src/commands/list.js Normal file
View file

@ -0,0 +1,51 @@
const CommandError = require('../util/command_error')
const { EmbedBuilder } = require('discord.js')
const { request } = require('undici');
module.exports = {
name: 'list',
description:['check the player list'],
trustLevel: 0,
aliases:['playerlist', 'plist', 'pl'],
usage:[""],
async execute (context) {
const bot = context.bot
const args = context.arguments
const players = bot.players
const source = context.source
const component = []
const url = await request(`https://eu.mc-api.net/v3/server/ping/${bot.options.host}`)
const server = await url.body.json()
for (const player of players) {
component.push({
translate: `%s \u203a %s [%s %s %s %s %s]`,
with: [
player.displayName ?? player.profile.name,
player.uuid,
{ text: `Ping:`, color: 'dark_green' },
{ text: `${player.latency}`, color: 'gold' },
{ text: '/', color: 'gray' },
{ text: `Gamemode:`, color: 'dark_purple' },
{ text: `${player.gamemode}`, color: 'gold' },
]
})
component.push('\n')
}
component.pop()
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, [
{ text: `Players: `, color:'gray' },
{ text: '(' , color: 'gray' },
{ text: `${JSON.stringify(bot.players.length)}`, color: 'gold' },
{ text: ` / `, color: 'gray' },
{ text: `${server.players.max}`, color: 'gold' },
{ text: ')\n', color: 'gray' },
component
])
// bot.tellraw(component)
},
discordExecute(context) {
const bot = context.bot
const players = bot.players
}
}
//what is wi
// IDK

61
src/commands/mcserver.js Normal file
View file

@ -0,0 +1,61 @@
const { request } = require('undici');
const CommandError = require('../util/command_error.js');
module.exports = {
name: 'mcserver',
trustLevel: 0,
aliases: [
// "say",
// "botsay",
],
description: 'look up minecraft server info',
async execute (context) {
const bot = context.bot;
const discordClient = context.discordClient;
const args = context.arguments;
const source = context.source;
try {
const url = await request(`https://eu.mc-api.net/v3/server/ping/${args[0]}`)
server = await url.body.json()
console.log(server)
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, [
{
text: `Ip \u203a ${args[0]}\n`,
color: 'gray'
},
{
text: `Players \u203a ${server.players.online}/${server.players.max}\n`,
color: 'gray'
},
{
text: `Version \u203a ${server.version.name}\n`,
color: 'gray',
},
{
text: "Motd \u203a\n",
color: 'gray',
},
server.description,
])// error: 'Ping Failed',
} catch (error) {
if (error.toString() === "TypeError: Cannot read properties of undefined (reading 'online')") {
bot.tellraw({ text: 'unable to ping server make sure the ip is correct', color: 'dark_red' })
} else {
bot.tellraw(error.toString())
}
}
}
}
/*
try {
const server = await request(`https://eu.mc-api.net/v3/server/ping/${interaction.options.getString('ip')}`);
json = await server.body.json()
console.log((json))
const Embed = new EmbedBuilder()
.setColor(`${config.colors.commands.embed}`)
.setTitle(`${this.data.name} Command`)
setDescription(
`IP \u203a ${interaction.options.getString('ip')}\nPlayer Count \u203a ${json.players.online}/${json.players.max}\nOnline \u203a ${json.online}\n
Version \u203a ${json.version.name}\nMotd \u203a ${JSON.stringify(json.description)}`)
.setThumbnail(`${json.favicon}`)
*/

25
src/commands/netmsg.js Normal file
View file

@ -0,0 +1,25 @@
const CommandError = require('../util/command_error.js')
module.exports = {
name: 'netmsg',
trustLevel: 0,
aliases: [
],
description: 'netmsg to other servers',
execute (context) {
const message = context.arguments.join(' ')
const bot = context.bot;
const source = context.source
//throw new CommandError('ohio')
const component = {
translate: '[%s] %s \u203a %s',
with: [
bot.options.host + ':' + bot.options.port,
source.player.displayName ?? source.player.profile.name,
message
]
}
for (const eachBot of bot.bots) eachBot.tellraw("@a", component)
}
}

View file

@ -0,0 +1,8 @@
module.exports = {
name: 'ovtest',
trustLevel: 2,
execute (context) {
const bot = context.bot
bot.chat.message('mrrrroww >:3')
}
}

21
src/commands/ping.js Normal file
View file

@ -0,0 +1,21 @@
module.exports = {
name: 'ping',
trustLevel: 0,
execute (context) {
const source = context.source;
const bot = context.bots;
if (context.arguments.length !== 0) {
const argumentList = []
for (const argument of context.arguments) {
if (argumentList.length !== 0) argumentList.push(' ')
argumentList.push(argument)
}
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, { text: 'Ping Arguments: ', extra: argumentList }, false)
return
}
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, 'Pong!', false)
}
}

14
src/commands/reconnect.js Normal file
View file

@ -0,0 +1,14 @@
module.exports = {
name: 'reconnect',
trustLevel: 1,
aliases: [
"end",
"recon",
],
description: 'reconnect the bot',
execute (context) {
const bot = context.bot
const message = context.arguments.join(' ')
bot._client.end()
}
}

21
src/commands/test.js Normal file
View file

@ -0,0 +1,21 @@
const CommandError = require('../util/command_error')
module.exports = {
name: 'test',
trustLevel: 0,
execute (context) {
if (context.arguments.length !== 0) {
const argumentList = []
for (const argument of context.arguments) {
if (argumentList.length !== 0) argumentList.push(' ')
argumentList.push(argument)
}
bot.tellraw({ text: 'Hello, world! Arguments: ', extra: argumentList }, false)
return
}
bot.tellraw('Hello, world!', false)
}
}

78
src/commands/urban.js Normal file
View file

@ -0,0 +1,78 @@
const CommandError = require('../util/command_error')
const { EmbedBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, SlashCommandBuilder } = require('discord.js');
const { request } = require('undici');
module.exports = {
name: 'urban',
description:['urban dictionary'],
aliases:['urbandictionary'],
trustLevel: 0,
usage:[
"all <definition>",
"single <definition>",
],
async execute (context) {
const source = context.source
const args = context.arguments
const bot = context.bot
const prefix = [
{ text: '[', color: 'dark_gray' },
{ text: 'Urban', color: '#B72A00' },
{ text: '] ', color: 'dark_gray'}
]
let component = [];
let term = `${args.join(' ')}`
const query = new URLSearchParams({ term });
const dictResult = await request(`https://api.urbandictionary.com/v0/define?${query}`);
const { list } = await dictResult.body.json();
if (!list.length) {
bot.sendError('No results found');
}
for (const definitions of list) {
component.push(prefix, [
{
text: `${definitions.definition.replaceAll('\r','').replaceAll('[', '\xa71\xa7n\xa7o').replaceAll(']','\xa7r\xa77')}\n`,
color: 'gray',
underlined: false,
italic: false,
translate:"",
hoverEvent: {
action:"show_text",
value: [
{
text: `Example \u203a \n ${definitions.example.replaceAll('\r', '').replaceAll('[', '\xa71\xa7n\xa7o').replaceAll(']','\xa7r\xa77')}`,
color: 'dark_blue'
},
{
text: `Word \u203a ${definitions.word.replaceAll('\r', '').replaceAll('[', '\xa71\xa7n\xa7o').replaceAll(']','\xa7r\xa77')}\n`,
color: 'dark_blue',
},
{
text: `Author \u203a ${definitions.author.replaceAll('\r', '').replaceAll('[', '\xa71\xa7n\xa7o').replaceAll(']','\xa7r\xa77')}\n`,
color: 'dark_blue'
},
{
text: `written on \u203a ${definitions.written_on.replaceAll('\r', '').replaceAll('[', '\xa71\xa7n\xa7o').replaceAll(']','\xa7r\xa77')}\n`,
color: 'dark_blue'
},
{
text: `Rating \u203a Thumbs-Up ${definitions.thumbs_up} / Thumbs-Down ${definitions.thumbs_down}`,
color: 'gray'
}
]
},
clickEvent: {
action: 'open_url',
value: `${definitions.permalink}`
}
},
])
}
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, component)
},
async discordExecute (context) {
const bot = context.bot;
const args = context.arguments;
const component = [];
}
}

18
src/commands/validate.js Normal file
View file

@ -0,0 +1,18 @@
module.exports = {
name: 'validate',
trustLevel: 1,
aliases: [
"val"
],
description: 'validate through the bot',
execute (context) {
const bot = context.bot;
const args = context.arguments;
const source = context.source;
if (args[0] === bot.trusted) {
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, { text: "Valid Trusted hash", color: "dark_green" });
} if (args[0] === bot.owner) {
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, { text: "Valid Owner hash", color: "dark_green" });
}
}
}

View file

@ -0,0 +1,18 @@
prefixes:
- "!"
discord:
token: "discord bot token here"
prefix: "!"
invite: "discord server invite here"
keys:
trusted: "trusted key here"
owner: "owner key here"
bots:
- host: "localhost"
username: "FNFBoyfriendBot"
version: "1.20.2"
reconnectDelay: 6000
channelId: "channel id here"

28
src/index.js Normal file
View file

@ -0,0 +1,28 @@
const createBot = require('./bot.js');
const readline = require('readline');
const loadModules = require('./util/loadModules');
const js_yaml = require('js-yaml');
const fs = require('fs');
const path = require('path');
const { Client, GatewayIntentBits } = require('discord.js');
const { MessageContent, GuildMessages, Guilds } = GatewayIntentBits;
const discordClient = new Client({ intents: [Guilds, GuildMessages, MessageContent] });
console.log('Starting FNFBoyfriendBot');
try {
config = js_yaml.load(fs.readFileSync(path.join(__dirname, '../', 'config.yml')))
} catch (e) {
console.log(e.stack);
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
})
const bots = [];
for (const options of config.bots) {
const bot = createBot(options);
bots.push(bot);
bot.bots = bots;
discordClient.login(config.discord.token);
loadModules(bot, options, config, discordClient);
bot.console.useReadlineInterface(rl);
}

6
src/modules/boot.js Normal file
View file

@ -0,0 +1,6 @@
function boot (bot, options, discordClient, config) {
bot.on("packet.login", (data) => {
bot.chat.message('&9FNF&3Boyfriend&1Bot &fcreated by &4Parker&02991');
}) // &9 &3 &1
}
module.exports = boot;

144
src/modules/chat.js Normal file
View file

@ -0,0 +1,144 @@
const loadPrismarineChat = require('prismarine-chat')
const KaboomChatParser = require('../util/ChatParsers/Kaboom')
const ChipmunkModChatParser = require('../util/ChatParsers/ChipmunkMod')
function tryParse (json) {
try {
return JSON.parse(json)
} catch (error) {
return { text: '' }
}
}
//what was changed??
function chat (bot, options, config) {
let ChatMessage
bot.on('registry_ready', registry => {
ChatMessage = loadPrismarineChat(registry)
})
bot.chatParsers = [KaboomChatParser, ChipmunkModChatParser]
bot.on('packet.profileless_chat', packet => {
const message = tryParse(packet.message)
const sender = tryParse(packet.name)
bot.emit('profileless_chat', {
message,
type: packet.type,
sender
})
bot.emit('message', message)
tryParsingMessage(message, { senderName: sender, players: bot.players, getMessageAsPrismarine: bot.getMessageAsPrismarine })
})
bot.on('packet.player_chat', packet => {
const unsigned = tryParse(packet.unsignedChatContent)
bot.emit('player_chat', { plain: packet.plainMessage, unsigned, senderUuid: packet.senderUuid })
bot.emit('message', unsigned)
tryParsingMessage(unsigned, { senderUuid: packet.senderUuid, players: bot.players, getMessageAsPrismarine: bot.getMessageAsPrismarine })
})
bot.on('packet.system_chat', packet => {
const message = tryParse(packet.content)
if (message.translate === 'advMode.setCommand.success') return // Ignores command set message
bot.emit('system_chat', { message, actionbar: packet.isActionBar })
if (packet.isActionBar) {
return
}
bot.emit('message', message)
tryParsingMessage(message, { players: bot.players, getMessageAsPrismarine: bot.getMessageAsPrismarine })
})
function tryParsingMessage (message, data) {
let parsed
for (const parser of bot.chatParsers) {
parsed = parser(message, data)
if (parsed) break
}
if (!parsed) return
bot.emit('parsed_message', parsed)
}
bot.getMessageAsPrismarine = message => {
try {
if (ChatMessage !== undefined) {
return new ChatMessage(message)
}
} catch {}
return undefined
}
/*
bot.chat = message => {
const acc = 0
const bitset = Buffer.allocUnsafe(3)
bitset[0] = acc & 0xFF
bitset[1] = (acc >> 8) & 0xFF
bitset[2] = (acc >> 16) & 0xFF
bot._client.write('chat_message', {
message,
timestamp: BigInt(Date.now()),
salt: 0n,
offset: 0,
acknowledged: bitset
})
}
*/
bot.chat = {
message: message => {
const acc = 0;
const bitset = Buffer.allocUnsafe(3);
bitset[0] = acc & 0xFF;
bitset[1] = (acc >> 8) & 0xFF;
bitset[2] = (acc >> 16) & 0xFF;
bot._client.write('chat_message', {
message: message?.substring(0, 256),
timestamp: BigInt(Date.now()),
salt: 0n,
offset: 0,
acknowledged: bitset
})
},
command: command => {
bot._client.write('chat_command', {
command: command?.substring(0, 256),
timestamp: BigInt(Date.now()),
salt: 0n,
argumentSignatures: [],
signedPreview: false,
messageCount: 0,
acknowledged: Buffer.alloc(3),
previousMessages: []
})
}
}
// console.log(bot.chat.sendMessage)
/*
bot.command = command => {
bot._client.write('chat_command', {
command,
timestamp: BigInt(Date.now()),
salt: 0n,
argumentSignatures: [],
signedPreview: false,
messageCount: 0,
acknowledged: Buffer.alloc(3),
previousMessages: []
})
}
*/
// bot.tellraw = (message, selector = '@a') => bot.core.run('minecraft:tellraw @a ' + JSON.stringify(message)) // ? Should this be here?
}
module.exports = chat;

View file

@ -0,0 +1,74 @@
function core (bot, options, config) {
bot.core = {
area: {
start: options.core?.area.start ?? { x: 0, y: 0, z: 0 },
end: options.core?.area.end ?? { x: 15, y: 0, z: 15 }
},
position: null,
currentBlockRelative: { x: 0, y: 0, z: 0 },
refill () {
const pos = bot.core.position
const { start, end } = bot.core.area
if (!pos) return
bot.chat.command(`minecraft:fill ${pos.x + start.x} ${pos.y + start.y} ${pos.z + start.z} ${pos.x + end.x} ${pos.y + end.y} ${pos.z + end.z} repeating_command_block`)
},
move (pos = bot.position) {
bot.core.position = {
x: Math.floor(pos.x / 16) * 16,
y: 0,
z: Math.floor(pos.z / 16) * 16
}
bot.core.refill()
},
currentBlock () {
const relativePosition = bot.core.currentBlockRelative
const corePosition = bot.core.position
if (!corePosition) return null
return { x: relativePosition.x + corePosition.x, y: relativePosition.y + corePosition.y, z: relativePosition.z + corePosition.z }
},
incrementCurrentBlock () {
const relativePosition = bot.core.currentBlockRelative
const { start, end } = bot.core.area
relativePosition.x++
if (relativePosition.x > end.x) {
relativePosition.x = start.x
relativePosition.z++
}
if (relativePosition.z > end.z) {
relativePosition.z = start.z
relativePosition.y++
}
if (relativePosition.y > end.y) {
relativePosition.x = start.x
relativePosition.y = start.y
relativePosition.z = start.z
}
},
run (command) {
const location = bot.core.currentBlock()
if (!location) return
bot._client.write('update_command_block', { command: command.substring(0, 32767), location, mode: 1, flags: 0b100 })
bot.core.incrementCurrentBlock()
}
}
bot.on('move', () => {
bot.core.move(bot.position)
setTimeout(() => bot.core.run('say Hello, world!'), 1000)
})
}
module.exports = core;

View file

@ -0,0 +1,17 @@
function command_loop (bot, options, config) {
bot.cloop = {
list: [],
add (command, interval) {
this.list.push({ timer: setInterval(() => bot.core.run(command), interval), command, interval })
},
remove (index) {
clearInterval(this.list[index].timer)
},
clear () {
for (const cloop of this.list) clearInterval(cloop.timer)
this.list = []
}
}
}
module.exports = command_loop;

View file

@ -0,0 +1,96 @@
const fs = require('fs');
const path = require('path');
const CommandError = require('../util/command_error.js');
const CommandSource = require('../util/command_source');
function command_manager (bot, options, config, discordClient) {
bot.commandManager = {
commands: {},
commandlist: [],
execute (source, commandName, args) {
const command = this.getCommand(commandName.toLowerCase())
try {
if (!command || !command.execute) throw new CommandError({ translate: 'Unknown command: %s', with: [commandName] })
if (command.trustLevel === 1 && bot.trusted) {
const hash = args[0]
if (args.length === 0 && bot.trusted && bot.owner && !source.sources.console) throw new CommandError({ text: "Please provide an trusted or owner hash" })
if (args[0] !== bot.trusted && args[0] !== bot.owner && !source.sources.console) throw new CommandError({ translate: 'Invalid trusted or owner hash', color: 'dark_red' })
}
if (command.trustLevel === 2 && bot.owner) {
if (args.length === 0 && bot.owner) throw new CommandError({ text: "Please provide an owner hash" })
if (args[0] !== bot.owner) throw new CommandError({ translate: 'Invalid owner hash', color: 'dark_red' })
} else if (command.trustLevel === 3 && !source.sources.console) {
throw new CommandError('This command can only be ran via console');
}
if (!command.discordExecute && command && source.sources.discord) {
throw new CommandError(`${command.name} command is not supported in discord!`)
} else if (command.discordExecute && command && source.sources.discord) {
return command.discordExecute({ bot, source, arguments: args, config, discordClient })
} else if (command.execute && command && !source.sources.discord) {
return command.execute({ bot, source, arguments: args, config, discordClient})
}
} catch (error) {
console.error(error)
if (error instanceof CommandError) bot.tellraw("@a", { text: error.message, color: "dark_red" }) //bot.tellraw({ text: `${}`, color: "dark_red" })
else bot.tellraw("@a", { translate: 'command.failed', color: "dark_red", hoverEvent: { action: 'show_text', contents: `${error.stack}` } })
}
},
executeString (source, command) {
const [commandName, ...args] = command.split(' ')
return this.execute(source, commandName, args)
},
discordExecute(source, command) {
const [commandName, ...args] = command.split(" ");
if (source?.sources?.discord && !source.sources.console) {
return this.discordExecute(source, commandName, args)
}
},
register (command) {
this.commands[command.name] = command
if (command.aliases) {
command.aliases.map((a) => (this.commands[a] = command));
}
},
getCommand (name) {
return this.commands[name]
},
getCommands () {
return Object.values(this.commands)
}
}
commandlist = [];
for (const filename of fs.readdirSync(path.join(__dirname, '../commands'))) {
try {
const command = require(path.join(__dirname, '../commands', filename))
bot.commandManager.register(command)
bot.commandManager.commandlist.push(command)
} catch (error) {
console.error('Failed to load command', filename, ':', error)
}
}
let ratelimit = 0;
bot.on("parsed_message", (data) => {
if (data.type !== "minecraft:chat") return;
const prefixes = config.prefixes;
prefixes.map((prefix) => {
const plainMessage = bot.getMessageAsPrismarine(data.contents)?.toString();
if (!plainMessage.startsWith(prefix)) return
const command = plainMessage.substring(prefix.length)
const source = new CommandSource(data.sender, { discord: false, console: false }, true)
ratelimit++
setTimeout(() => {
ratelimit--
}, 1000)
if (ratelimit > 2) {
bot.tellraw(`@a[name="${source?.player?.profile?.name}"]`, { text: 'You are using commands too fast!', color: 'dark_red'})
} else {
bot.commandManager.executeString(source, command)
}
})
})
}
module.exports = command_manager;

50
src/modules/console.js Normal file
View file

@ -0,0 +1,50 @@
const CommandSource = require('../util/command_source')
function CommandConsole (bot, options, config) {
bot.console = {
readline: null,
consoleServer: 'all',
useReadlineInterface (rl) {
this.readline = rl
rl.on('line', line => {
if (bot.options.host !== this.consoleServer && this.consoleServer !== 'all') return
// bot.commandManager.executeString(bot.console.source, line)
if (line.startsWith('c.')) {
return bot.commandManager.executeString(bot.console.source, line.substring(2))
} if (line.startsWith("")) {
return bot.commandManager.executeString(bot.console.source, `echo ${line.substring(0)}`)
}
})
rl.on('close', () => {
this.readline = null
})
const originalConsole = console
this.log = (...args) => {
rl.output.write('\x1b[2K\r')
originalConsole.log(args.toString())
rl._refreshLine()
}
}
}
bot.console.logs = function log (message) {
console.log(`[${new Date().toLocaleString("en-US", { timeZone:"America/CHICAGO" })}] [${options.host}:${options.port}] ${message}`)
}
bot.console.source = new CommandSource(null, { console: true, discord: false });
bot.console.source.sendFeedback = message => {
const ansi = bot.getMessageAsPrismarine(message)?.toAnsi()
bot.console.logs(ansi)
// cosnole.log(ansi)
}
bot.on('message', message => {
const ansi = bot.getMessageAsPrismarine(message)?.toAnsi()
const string = bot.getMessageAsPrismarine(message)?.toString()
bot.console.logs(`${ansi}`)
// this.log('sus')
})
}
module.exports = CommandConsole;

182
src/modules/discord.js Normal file
View file

@ -0,0 +1,182 @@
// TODO: Maybe move client creation elsepwhere
const { Client, GatewayIntentBits, interaction } = require('discord.js')
const { MessageContent, GuildMessages, Guilds } = GatewayIntentBits
const fixansi = require('../util/ansi');
const CommandSource = require('../util/command_source')
const client = new Client({ intents: [Guilds, GuildMessages, MessageContent] })
const util = require('util')
function discord(bot, options, config, discordClient) {
// client.login(config.discord.token)
if (!options?.channelId) {
bot.discord = {
invite: config.discord?.invite
}
return
}
bot.discord = {
client: discordClient,
channel: undefined,
invite: config.discord.invite || undefined,
prefix: config.discord.prefix,
// presence: bot.discord.presence,
token: config.discord.token,
}
discordClient.on('ready', (context) => {
bot.discord.channel = discordClient.channels.cache.get(options.channelId)
/* client.user.setPresence({
activities: [{
name: `${bot.discord.presence.name}`,
type: bot.discord.presence.type
}],
status: `${bot.discord.presence.status}`
});*/
})
let discordQueue = []
setInterval(() => {
if (discordQueue.length === 0) return
try {
bot?.discord?.channel?.send(`\`\`\`ansi\n${discordQueue.join('\n').substring(0, 1984)}\n\`\`\``)
} catch (error) {
bot.console.error(error.stack)
}
discordQueue = []
}, 2000)
function sendDiscordMessage(message) {
discordQueue.push(message)
}
function sendComponent(message) {
const ansi = bot.getMessageAsPrismarine(message)?.toAnsi().replaceAll('```\u001b[9```' + '```\u001b[3```').replaceAll('https://discord','https:\rdiscord')?.replaceAll('discord.gg', 'discord.\rgg');
try {
sendDiscordMessage(fixansi(ansi.replaceAll('`', '`\u200b')))
} catch (e) {
bot.console.error(`Error sending a message to Discord:\n${e.message}`)
sendDiscordMessage(e.message)
}
}
bot.on('message', message => {
sendComponent(message)
})
function messageCreate(message, source) {
bot.discord.Message = message
if (message.author.id === bot.discord.client.user.id) return
if (message.channel.id !== bot.discord.channel.id) return
if (message.content.startsWith(config.discord.prefix)) { // TODO: Don't hardcode this
const source = new CommandSource({
profile: {
name: message?.member?.displayName
}
}, {
discord: true,
console: false
}, false, message)
bot.sendFeedback = message => {
sendComponent(message)
}
bot.commandManager.executeString(source, message.content.substring(config.discord.prefix.length))
return
}
const tag = {
translate: '[%s] %s \u203a %s',
with: [{
translate: '%s%s%s %s',
bold: false,
with: [{
text: 'FNF',
bold: false,
color: 'blue'
},
{
text: 'Boyfriend',
bold: false,
color: 'dark_aqua'
},
{
text: 'Bot',
bold: false,
color: 'dark_blue'
},
{
text: 'Discord',
bold: false,
color: 'dark_blue'
}
],
clickEvent: bot.discord.invite ? {
action: 'open_url',
value: bot.discord.invite
} : undefined,
hoverEvent: {
action: 'show_text',
contents: 'Click to join the discord'
}
},
{
text: message?.member?.displayName
},
message.content
]
}
if (message.attachments.size > 0) {
message.attachments.forEach(Attachment => {
bot.tellraw('@a', [tag, {
text: ' ' ? ' [Attachment] ' : ' [Attachment] ',
hoverEvent: {
action: 'show_text',
contents: 'Click here to view attachment'
},
clickEvent: {
action: 'open_url',
value: `${Attachment.url}`
}
}])
})
} else {
bot.tellraw('@a', tag);
}
}
discordClient.on('messageCreate', messageCreate)
process.on("uncaughtException", (e) => {
// sendDiscordMessage("uncaught " + e.stack);
});
/*
function fixansi(message) {
const ansilist = {
"\x1B\[93m": "\x1B[33m", // Yellow
"\x1B\[96m": "\x1B[36m", // Blue
"\x1B\[94m": "\x1B[34m", // Discord Blue
"\x1B\[90m": "\x1B[30m", // Gray
"\x1B\[91m": "\x1B[31m", // Light Red
"\x1B\[95m": "\x1B\[35m", // Pink
"\x1B\[92m": "\x1B\[32m", // Green
"\x1B\[0m": "\x1B\[0m\x1B\[37m", // White
"\x1B\[97m": "\x1B\[0m\x1B\[37m", // White
};
let i = message;
for (const ansi in ansilist) {
if (ansilist.hasOwnProperty(ansi)) {
i = i.replace(new RegExp(escapeRegExpChars(ansi), 'g'), ansilist[ansi]);
function escapeRegExpChars(text) {
return text.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
}
}
return i;
}*/
}
module.exports = discord;

View file

@ -0,0 +1,81 @@
function player_list (bot, options, config) {
bot.players = []
bot.on('packet.player_info', packet => {
const actions = []
if (packet.action & 0b000001) actions.push(addPlayer)
if (packet.action & 0b000010) actions.push(initializeChat)
if (packet.action & 0b000100) actions.push(updateGamemode)
if (packet.action & 0b001000) actions.push(updateListed)
if (packet.action & 0b010000) actions.push(updateLatency)
if (packet.action & 0b100000) actions.push(updateDisplayName)
for (const entry of packet.data) {
for (const action of actions) {
action(entry)
}
}
})
bot.on('packet.player_remove', ({ players }) => {
// TODO: Add player removal (with validation)
for (const player of players) {
bot.players = bot.players.filter(entry => entry.uuid !== player)
}
})
function addPlayer (entry) {
bot.players = bot.players.filter(_entry => _entry.uuid !== entry.uuid)
bot.players.push({
uuid: entry.uuid,
profile: { name: entry.player.name, properties: entry.player.properties },
chatSession: undefined,
gamemode: undefined,
listed: undefined,
latency: undefined,
displayName: undefined
})
}
function initializeChat (entry) {
// TODO: Handle chat sessions
}
function updateGamemode (entry) {
const target = bot.players.find(_entry => _entry.uuid === entry.uuid)
if (!target) return
target.gamemode = entry.gamemode
}
function updateListed (entry) {
const target = bot.players.find(_entry => _entry.uuid === entry.uuid)
if (!target) return
target.listed = entry.listed
}
function updateLatency (entry) {
const target = bot.players.find(_entry => _entry.uuid === entry.uuid)
if (!target) return
target.latency = entry.latency
}
function updateDisplayName (entry) {
const target = bot.players.find(_entry => _entry.uuid === entry.uuid)
if (!target) return
try {
target.displayName = JSON.parse(entry.displayName)
} catch {
// do nothing
}
}
bot.on('end', () => (bot.players = []))
}
module.exports = player_list;

19
src/modules/position.js Normal file
View file

@ -0,0 +1,19 @@
function position (bot, options, config) {
bot.position = null
bot.on('packet.position', packet => {
bot.position = {
x: packet.flags & 1 ? (this.x + packet.x) : packet.x,
y: packet.flags & 2 ? (this.y + packet.y) : packet.y,
z: packet.flags & 4 ? (this.z + packet.z) : packet.z
}
bot._client.write('teleport_confirm', { teleportId: packet.teleportId })
bot.emit('move')
})
bot.on('end', () => { bot.position = null })
}
module.exports = position

14
src/modules/reconnect.js Normal file
View file

@ -0,0 +1,14 @@
const mc = require('minecraft-protocol')
function reconnect (bot, options) {
bot.reconnectDelay = options.reconnectDelay ?? 5000
bot.on('end', () => {
if (bot.reconnectDelay < 0) return
bot._client = mc.createClient(options)
bot.emit('init_client', bot._client)
})
}
module.exports = reconnect;

10
src/modules/registry.js Normal file
View file

@ -0,0 +1,10 @@
const createRegistry = require('prismarine-registry')
function registry (bot) {
bot.on('packet.login', packet => {
bot.registry = createRegistry(bot._client.version)
bot.emit('registry_ready', bot.registry)
})
}
module.exports = registry;

53
src/modules/selfcare.js Normal file
View file

@ -0,0 +1,53 @@
function selfcare (bot, options, config) {
let entityId;
let permissionLevel = 2;
let gameMode;
let commandSpy = false;
let vanished = false;
let prefix = false;
// You now have the tag: &8[&bPrefix&8: &3~&8]
// You no longer have a tag
bot.on('message', (message) => {
const stringMessage = bot.getMessageAsPrismarine(message).toString();
if (stringMessage.startsWith("Successfully enabled CommandSpy")) commandSpy = true;
else if (stringMessage?.startsWith("Successfully disabled CommandSpy")) commandSpy = false;
else if (stringMessage === `Vanish for ${bot.options.username}: enabled`) vanished = true;
else if (stringMessage === `Vanish for ${bot.options.username}: disabled`) vanished = false;
else if (stringMessage === `You now have the tag: &8[&bPrefix&8: &3${config.prefixes[0]}&8]` || stringMessage === "Something went wrong while saving the prefix. Please check console.") prefix = true;
else if (stringMessage?.startsWith("You now have the tag: ") || stringMessage === "You no longer have a tag") prefix = false
})
// else if (stringmessage?.startsWith("You now have the tag: ") || JSON?.stringify(message) === '{"text":"You no longer have a tag"}') prefix = false
bot.on('packet.entity_status', packet => {
if (packet.entityId !== entityId || packet.entityStatus < 24 || packet.entityStatus > 28) return
permissionLevel = packet.entityStatus - 24
})
bot.on('packet.game_state_change', packet => {
if (packet.reason !== 3) return // Reason 3 = Change Game Mode
// if (packet.reason !== 4) return // Reason 4 = end credits
gameMode = packet.gameMode;
});
bot.on("packet.game_state.change", packet => {
})
let timer;
bot.on('packet.login', (packet) => {
entityId = packet.entityId;
gameMode = packet.gameMode;
timer = setInterval(() => {
if (permissionLevel < 2) bot.chat.command('op @s[type=player]');
else if (gameMode !== 1) bot.chat.command('gamemode creative @s[type=player]');
else if (!commandSpy) bot.chat.command('commandspy on');
else if (!vanished) bot.core.run(`vanish ${bot.options.username} on`);
else if (!prefix) bot.chat.command(`prefix &8[&bPrefix&8: &3${config.prefixes[0]}&8]`);
else if (gameMode !== 4) bot._client.write("client_command", { actionId: 0 });
}, 1000);
});
bot.on('end', () => {
if (timer) clearInterval(timer)
prefix = false;
commandSpy = false;
vanished = false;
prefix = false;
});
}
module.exports = selfcare;

6
src/modules/tellraw.js Normal file
View file

@ -0,0 +1,6 @@
function tellraw (bot, options, config) {
bot.tellraw = (selector, message) => {
bot.core.run(`minecraft:tellraw ${selector} ` + JSON.stringify(message))
}
}
module.exports = tellraw;

10
src/modules/validation.js Normal file
View file

@ -0,0 +1,10 @@
const crypto = require("crypto");
function validation (bot, options, config) {
bot.trusted = "";
let trusted;
let hashRegenInterval = setInterval(() => {
bot.trusted = crypto.createHash('sha256').update(Math.floor(Date.now() / 5000) + config.keys.trusted).digest('hex').substring(0, 16)
bot.owner = crypto.createHash('sha256').update(Math.floor(Date.now() / 5000) + config.keys.owner).digest('hex').substring(0, 16)
}, 2000)
}
module.exports = validation;

View file

@ -0,0 +1,35 @@
function chipmunkmod (message, data, context, bot) {
try {
if (message === null || typeof message !== 'object') return
if (message.with?.length < 3 || (message.translate !== '[%s] %s %s' && message.translate !== '%s %s %s')) return
const senderComponent = message.with[1]
// wtf spam again -
//console.log(senderComponent)//wtf...
const contents = message.with[2]
// spam lol - console.log(contents)
let sender
const hoverEvent = senderComponent.hoverEvent
//console.log(JSON.stringify(hoverEvent))
if (hoverEvent?.action === 'show_entity') {
const id = hoverEvent.contents.id
//
sender = data.players.find(player => player.uuid === id)
} else {
const stringUsername = data.getMessageAsPrismarine(senderComponent).toString() // TypeError: data.getMessageAsPrismarine is not a function
sender = data.players.find(player => player.profile.name) //=== stringusername)
}
if (!sender) return null
return { sender, contents, type: 'minecraft:chat', senderComponent }
} catch(e) {
console.error(e)
}
}
module.exports = chipmunkmod

View file

@ -0,0 +1,41 @@
const util = require('util')
function parseMessage (message, data) {
if (message === null || typeof message !== 'object') return
if (message.text !== '' || !Array.isArray(message.extra) || message.extra.length < 3) return
const children = message.extra
const prefix = children[0]
let displayName = data.senderName ?? { text: '' }
let contents = { text: '' }
if (isSeparatorAt(children, 1)) { // Missing/blank display name
if (children.length > 3) contents = children[3]
} else if (isSeparatorAt(children, 2)) {
displayName = children[1]
if (children.length > 4) contents = children[4]
} else {
return undefined
}
const playerListDisplayName = { extra: [prefix, displayName], text: '' }
let sender
if (data.uuid) {
sender = data.players.find(player => player.uuid === data.senderUuid)
} else {
const playerListDisplayName = { extra: [prefix, displayName], text: '' }
sender = data.players.find(player => util.isDeepStrictEqual(player.displayName, playerListDisplayName))
}
if (!sender) return undefined
return { sender, contents, type: 'minecraft:chat', displayName }
}
function isSeparatorAt (children, start) {
return (children[start]?.text === ':' || children[start]?.text === '\xa7f:') && children[start + 1]?.text === ' '
}
module.exports = parseMessage

26
src/util/ansi.js Normal file
View file

@ -0,0 +1,26 @@
function ansi (message) {
const ansilist = {
"\x1B\[93m": "\x1B[33m", // Yellow
"\x1B\[96m": "\x1B[36m", // Blue
"\x1B\[94m": "\x1B[34m", // Discord Blue
"\x1B\[90m": "\x1B[30m", // Gray
"\x1B\[91m": "\x1B[31m", // Light Red
"\x1B\[95m": "\x1B\[35m", // Pink
"\x1B\[92m": "\x1B\[32m", // Green
"\x1B\[0m": "\x1B\[0m\x1B\[37m", // White
"\x1B\[97m": "\x1B\[0m\x1B\[37m", // White
};
let i = message;
for (const ansi in ansilist) {
if (ansilist.hasOwnProperty(ansi)) {
i = i.replace(new RegExp(escapeRegExpChars(ansi), 'g'), ansilist[ansi]);
function escapeRegExpChars(text) {
return text.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
}
}
}
return i;
}
module.exports = ansi;

16
src/util/command_error.js Normal file
View file

@ -0,0 +1,16 @@
// TODO: Improve how messages are stringified
const ChatMessage = require('prismarine-chat')('1.20.1')
const stringify = message => new ChatMessage(message).toString()
class CommandError extends Error {
constructor (message, filename, lineError) {
super(stringify(message), filename, lineError)
this.name = 'CommandError'
this._message = message
}
get message () {
return stringify(this._message)
}
}
module.exports = CommandError

View file

@ -0,0 +1,14 @@
class CommandSource {
constructor (player, sources) {
this.player = player;
this.sources = sources;
}
/* sendFeedback () {}
sendError (message) {
this.sendFeedback([{ text: '', color: 'dark_red' }, message], false)
}*/
}
module.exports = CommandSource

20
src/util/loadModules.js Normal file
View file

@ -0,0 +1,20 @@
const fs = require("fs");
const path = require("path");
const readline = require("readline");
/*const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
})*/
function loadModules (bot, options, config, discordClient) {
bot.loadModule = module => module(bot, options, config, discordClient)
for (const filename of fs.readdirSync(path.join(__dirname, '../', 'modules'))) {
try {
const module = require(path.join(__dirname, '../', 'modules', filename))
bot.loadModule(module)
} catch (error) {
console.error('Failed to load module', filename, ':', error)
}
}
}
module.exports = loadModules;

10
src/util/usernameGen.js Normal file
View file

@ -0,0 +1,10 @@
function usernameGen () {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
let username = '';
for (let i = 0; i < 10; i++ ) {
const randomIndex = Math.floor(Math.random() * characters.length);
username += characters[randomIndex];
}
return username;
}
module.exports = usernameGen;