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) } function getHexFromIdentifyer(identifyer) { let fillStyle; switch (identifyer) { case '0': fillStyle = '#000000' // Black break case '1': fillStyle = '#0000AA' // Dark Blue break case '2': fillStyle = '#00AA00' // Dark Green break case '3': fillStyle = '#00AAAA' // Dark Aqua break case '4': fillStyle = '#AA0000' // Dark Red break case '5': fillStyle = '#AA00AA' // Dark Purple break case '6': fillStyle = '#FFAA00' // Gold break case '7': fillStyle = '#AAAAAA' // Gray break case '8': fillStyle = '#555555' // Dark Gray break case '9': fillStyle = '#5555FF' // Blue break case 'a': fillStyle = '#55FF55' // Green break case 'b': fillStyle = '#55FFFF' // Aqua break case 'c': fillStyle = '#FF5555' // Red break case 'd': fillStyle = '#FF55FF' // Light Purple break case 'e': fillStyle = '#FFFF55' // Yellow break case 'f': fillStyle = '#FFFFFF' // White break default: fillStyle = '#000000' // Default to Black if no match } return fillStyle } async function sendWebhookMessage(guildMsg) { const canvas = createCanvas(800, 45) const context = canvas.getContext('2d') context.font = '28px minecraft' const username = guildMsg.sender.rawUsername const hypixelRank = guildMsg.sender.rawHypixelRank const guildRank = guildMsg.sender.rawGuildRank const message = guildMsg.message let x = 28 let y = 50 // Draw text with colors let string_to_build = `${hypixelRank} ${username}` let index = 0 let fillStyle = '#AAAAAA' while (index < string_to_build.length) { if (string_to_build.charAt(index) === '§') { fillStyle = getHexFromIdentifyer(string_to_build.charAt(index + 1)) index++ index++ } context.fillStyle = fillStyle context.fillText(string_to_build.charAt(index), x, y) x += context.measureText(string_to_build.charAt(index)).width // + 10 index++ } context.fillStyle = '#ffffff' context.fillText(`: ${message}`, x, y) const buffer = canvas.toBuffer('image/png') 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') const test_str = '§b[MVP§0++§b] illyum §e[STAFF]' const guildMsgSender = new GuildMessageSender('illyum', '§b[MVP§0++§b]', '§e[STAFF]') const guildMessage = new GuildMessage('This is a test!', guildMsgSender) async function main() { try { await sendWebhookMessage(guildMessage); // Additional async calls can be made here } catch (error) { console.error(error); } } main();