const fs = require('fs') const axios = require('axios') const mineflayer = require('mineflayer') const { EventEmitter } = require('events') const { EmbedBuilder, hyperlink, WebhookClient } = require('discord.js'); const { registerFont, createCanvas } = require('canvas'); function stripChatColors(txt) { const formattingRegex = /§[0-9a-fklmnor]+|[\[\]:]+/g; return txt.replace(formattingRegex, ''); } class GuildMessageSender { constructor(rawUsername, rawHypixelRank, rawGuildRank) { this.rawUsername = rawUsername this.rawHypixelRank = rawHypixelRank this.rawGuildRank = rawGuildRank } getCleanUsername() { return stripChatColors(this.rawUsername) } getCleanHypixelRank() { return stripChatColors(this.rawHypixelRank) } getCleanGuildRank() { return stripChatColors(this.rawGuildRank) } } class GuildMessage { constructor(message, sender) { this.message = message this.sender = sender } } class OfficerMessage { constructor(message, sender) { this.message = message this.sender = sender } } function parseGuildMessage(jsonMsg) { const message_details = jsonMsg.json.extra let message_prefix = message_details[0].text let hypixel_rank = null let username = null let guild_rank = null let eventType = 'null' let sender_contents = null if (message_prefix.includes('§2Guild >')) { eventType = 'guildmsg'; sender_contents = message_prefix.replace('§2Guild >', '') } else if (message_prefix.includes('§3Officer >')) { eventType = 'officermsg'; sender_contents = message_prefix.replace('§3Officer >', '') } let message_arr = sender_contents.trim().split(' ') // Parse guild member details (with hypixel rank) if (message_arr[0].includes('[')) { hypixel_rank = message_arr[0]; username = message_arr[1]; guild_rank = message_arr[2].replace(':', '') } // Parse guild member details (nons) else { hypixel_rank = ''; username = message_arr[0]; guild_rank = message_arr[1].replace(':', '') } // Skip messages sent by the bot if (stripChatColors(username) === bot.username) { return } const sender = new GuildMessageSender(username, hypixel_rank, guild_rank) let guildMessage = null if (eventType === 'guildmsg') { guildMessage = new GuildMessage(message_details[1].text, sender) } else if (eventType === 'officermsg') { guildMessage = new OfficerMessage(message_details[1].text, sender) } else { console.error('Error parsing guild message: unknown event type'); return } // Emit GuildMessage event chatEvents.emit(eventType, guildMessage) } async function sendWebhookMessage(guildMsg) { const canvas = createCanvas(800, 200) const context = canvas.getContext('2d') // Fill background context.fillStyle = '#313338' context.fillRect(0, 0, canvas.width, canvas.height) context.font = '24px minecraft' const username = guildMsg.sender.rawUsername const hypixelRank = guildMsg.sender.rawHypixelRank const guildRank = guildMsg.sender.rawGuildRank const message = guildMsg.message let x = 10 let y = 50 // Draw text with colors context.fillStyle = '#FFAA00' // Example color, modify as needed context.fillText(hypixelRank, x, y) x += context.measureText(hypixelRank).width + 10 context.fillStyle = '#55FF55' // Example color, modify as needed context.fillText(username, x, y) x += context.measureText(username).width + 10 context.fillStyle = '#AAAAFF' // Example color, modify as needed context.fillText(guildRank, x, y) x += context.measureText(guildRank).width + 10 context.fillStyle = '#FFFFFF' // Example color, modify as needed context.fillText(message, x, y) // Convert canvas to buffer const buffer = canvas.toBuffer('image/png') // Send image to Discord webhook const form = new FormData() form.append('file', new Blob([Buffer.from(buffer)]), 'message.png') await axios.post(webhookUrl, form, {}) } class ProudCircleBot { constructor(username) { this.username = username this.auth = 'microsoft' this.host = 'play.hypixel.net' this.version = '1.8.9' this.shouldReconnect = true this.initBot() } initBot() { this.bot = mineflayer.createBot({ "username": this.username, "auth": 'microsoft', "host": 'play.hypixel.net', "version": this.version }) this.initEvents() this.bot.emit('startup') this.listenToUserInput() } listenToUserInput() {} initEvents() { // Bot Startup this.bot.on('startup', async () => { console.log('Starting bot...') }) // Server login this.bot.on('login', async () => { let sock = this.bot._client.socket console.log(`Logged into ${sock.server ? sock.server : sock._host}`) }) // Disconnect from server this.bot.on('end', async (cause) => { console.log(`Disconnected from server: ${cause}`) if (reason === 'disconnect.quitting') { return } else { console.error('Unknown cause of disconnecting!') } // Auto Reconnect if (this.shouldReconnect) { console.log('Attempting to reconnect...') setTimeout(() => this.initBot(), 5000) } }) // Chat Message this.bot.on('message', async (jsonMsg, position) => { // Avoid hypixel cancer if (jsonMsg['extra'] && jsonMsg['extra'].length === 100) { return } let rawText = jsonMsg.toString() if (rawText === "Woah there, slow down!") { console.error("Server issued message spam warning") } if (!jsonMsg?.json?.extra || jsonMsg.json.extra.length === 0 || !jsonMsg.json.extra[0]) { return } // Check for guild messages // Guild/Officer chat/member join/member leave let extra_prefix = jsonMsg.json.extra[0].text if (extra_prefix.startsWith('§2Guild >') || extra_prefix.startsWith('§3Officer >')) { parseGuildMessage(jsonMsg) } }) // Custom Guild Message Event chatEvents.on('guildmsg', async (guildMsg) => { console.log(`Guild: ${guildMsg.sender.getCleanUsername()} ${guildMsg.message}`) await sendWebhookMessage(guildMsg) }) // Custom Officer Message Event chatEvents.on('officermsg', (officerMsg) => { console.log(`Officer: ${officerMsg.sender.getCleanUsername()} ${officerMsg.message}`) }) } } registerFont('fonts/Minecraftia-Regular.ttf', {family: 'Minecraft'}) const webhookUrl = 'https://discord.com/api/webhooks/1262482329671176232/yAHgxkP2JSBPpdjmz6mdABu5yRkXxatXcbzI91iAjy0jM0z1kRzE1HZqzK5OGXCmkqPk' const webhookClient = new WebhookClient({ url: webhookUrl }); const chatEvents = new EventEmitter() const bot = new ProudCircleBot('ProudCircle')