const lang = require("./en_us.json"); // translate message function uuidFromIntArray (arr) { const buf = Buffer.alloc(16) arr.forEach((num, index) => { buf.writeInt32BE(num, index * 4) }) return buf.toString('hex') } function simplify (data) { try { if (data === undefined) return data; function transform (value, type) { if (type === 'compound') { return Object.keys(value).reduce(function (acc, key) { acc[key] = simplify(value[key]) return acc }, {}) } if (type === 'list') { return value.value.map(function (v) { return transform(v, value.type) }) } return value } return transform(data.value, data.type) } catch (e) { return e; } } function processNbtMessage (msg) { try { if (!msg || msg.type === 'end') return null; if (typeof msg === 'string') return msg const simplified = simplify(msg); // Ensure nbt is defined elsewhere const json = JSON.stringify(simplified, (key, val) => { if (key === 'id' && Array.isArray(val)) return uuidFromIntArray(val); return val; }); return json; } catch (e) { return e; } } function inject(bot) { let playerchat = {}; // im think this can fix memory leak. let systemchat = {}; let profilelesschat = {}; let actionbar = {}; bot.on('system_chat', (packet) => { // system if (packet.isActionBar) { actionbar = {}; console.log(`Actionbar: ${packet}`); return; }; systemchat = {}; systemchat.jsonMsg = simplify(packet.content); systemchat.message = parseMinecraftMessage(simplify(packet.content)); systemchat.nocolor_message = parseMinecraftMessageNoColor(simplify(packet.content)); bot.emit('custom_systemchat', systemchat.message, systemchat, packet); bot.emit('custom_allchat', systemchat.message, systemchat, packet); }); bot.on('profileless_chat', (packet) => { // kinda player_chat profilelesschat = {}; profilelesschat.type = packet.type profilelesschat.formattedMessage = simplify(packet.message); profilelesschat.senderName = simplify(packet.name); profilelesschat.targetName = simplify(packet.target); switch (profilelesschat.type) { case 1: // /minecraft:me profilelesschat.message = parseMinecraftMessage({ "translate": "chat.type.emote", "with": [ profilelesschat.senderName, profilelesschat.formattedMessage ]}); profilelesschat.nocolor_msg = parseMinecraftMessageNoColor({ "translate": "chat.type.emote", "with": [ profilelesschat.senderName, profilelesschat.formattedMessage ]}); break; case 2: // player /minecraft:tell profilelesschat.message = parseMinecraftMessage({ translate: "commands.message.display.incoming", with: [ profilelesschat.senderName, profilelesschat.formattedMessage ], color: "gray", italic: true }); profilelesschat.nocolor_msg = parseMinecraftMessageNoColor({ translate: "commands.message.display.incoming", with: [ profilelesschat.senderName, profilelesschat.formattedMessage ], color: "gray", italic: true }); break; case 3: // you /minecraft:tell profilelesschat.message = parseMinecraftMessage({ translate: "commands.message.display.outgoing", with: [ profilelesschat.targetName, profilelesschat.formattedMessage ], color: "gray", italic: true }); profilelesschat.nocolor_msg = parseMinecraftMessageNoColor({ translate: "commands.message.display.outgoing", with: [ profilelesschat.targetName, profilelesschat.formattedMessage ], color: "gray", italic: true }); break; case 4: // player chat profilelesschat.message = parseMinecraftMessage(profilelesschat.formattedMessage); profilelesschat.nocolor_msg = parseMinecraftMessageNoColor(profilelesschat.formattedMessage); break; case 5: // profilelesschat.message = parseMinecraftMessage({ translate: 'chat.type.announcement', with: [ profilelesschat.senderName, profilelesschat.formattedMessage ]}); profilelesschat.nocolor_msg = parseMinecraftMessageNoColor({ translate: 'chat.type.announcement', with: [ profilelesschat.senderName, profilelesschat.formattedMessage ]}); break; case 6: // player /minecraft:teammsg || /teammsg profilelesschat.message = parseMinecraftMessage({ translate: 'chat.type.team.text', with: [ profilelesschat.targetName, profilelesschat.senderName, profilelesschat.formattedMessage ]}); profilelesschat.nocolor_msg = parseMinecraftMessageNoColor({ translate: 'chat.type.team.text', with: [ profilelesschat.targetName, profilelesschat.senderName, profilelesschat.formattedMessage ]}); break; case 7: // you /minecraft:teammsg || /teammsg profilelesschat.message = parseMinecraftMessage({ translate: 'chat.type.team.sent', with: [ profilelesschat.targetName, profilelesschat.senderName, profilelesschat.formattedMessage ]}); profilelesschat.nocolor_msg = parseMinecraftMessageNoColor({ translate: 'chat.type.team.sent', with: [ profilelesschat.targetName, profilelesschat.senderName, profilelesschat.formattedMessage ]}); break; default: console.log(`Unknown player_chat packet. Type: ${playerchat.type}`); console.log(packet); break; } bot.emit('custom_profilelesschat', profilelesschat.message, profilelesschat, packet) bot.emit('custom_allchat', profilelesschat.message, profilelesschat, packet) }) bot.on('player_chat', (packet) => { // player playerchat = {}; playerchat.plainMessage = packet.plainMessage; playerchat.type = packet.type; playerchat.sender = packet.senderUuid; playerchat.unsignedContent = simplify(packet.unsignedChatContent); playerchat.senderName = simplify(packet.networkName); playerchat.targetName = simplify(packet.networkTargetName); switch (playerchat.type) { // vanish off case 1: // /minecraft:me playerchat.message = parseMinecraftMessage({ "translate": "chat.type.emote", "with": [ playerchat.senderName, playerchat.plainMessage ]}); playerchat.nocolor_msg = parseMinecraftMessageNoColor({ "translate": "chat.type.emote", "with": [ playerchat.senderName, playerchat.plainMessage ]}); break; case 2: // player /minecraft:tell playerchat.message = parseMinecraftMessage({ translate: "commands.message.display.incoming", with: [ playerchat.senderName, playerchat.plainMessage ], color: "gray", italic: true }); playerchat.nocolor_msg = parseMinecraftMessageNoColor({ translate: "commands.message.display.incoming", with: [ playerchat.senderName, playerchat.plainMessage ], color: "gray", italic: true }); break; case 3: // you /minecraft:tell playerchat.message = parseMinecraftMessage({ translate: "commands.message.display.outgoing", with: [ playerchat.targetName, playerchat.plainMessage ], color: "gray", italic: true }); playerchat.nocolor_msg = parseMinecraftMessageNoColor({ translate: "commands.message.display.outgoing", with: [ playerchat.targetName, playerchat.plainMessage ], color: "gray", italic: true }); break; case 4: // player chat playerchat.message = parseMinecraftMessage(playerchat.unsignedContent); playerchat.nocolor_msg = parseMinecraftMessageNoColor(playerchat.unsignedContent); break; case 5: // playerchat.message = parseMinecraftMessage({ translate: 'chat.type.announcement', with: [ playerchat.senderName, playerchat.plainMessage ]}); playerchat.nocolor_msg = parseMinecraftMessageNoColor({ translate: 'chat.type.announcement', with: [ playerchat.senderName, playerchat.plainMessage ]}); break; case 6: // player /minecraft:teammsg || /teammsg playerchat.message = parseMinecraftMessage({ translate: 'chat.type.team.text', with: [ playerchat.targetName, playerchat.senderName, playerchat.plainMessage ]}); playerchat.nocolor_msg = parseMinecraftMessageNoColor({ translate: 'chat.type.team.text', with: [ playerchat.targetName, playerchat.senderName, playerchat.plainMessage ]}); break; case 7: // you /minecraft:teammsg || /teammsg playerchat.message = parseMinecraftMessage({ translate: 'chat.type.team.sent', with: [ playerchat.targetName, playerchat.senderName, playerchat.plainMessage ]}); playerchat.message = parseMinecraftMessageNoColor({ translate: 'chat.type.team.sent', with: [ playerchat.targetName, playerchat.senderName, playerchat.plainMessage ]}); break; default: console.log(`Unknown player_chat packet. Type: ${playerchat.type}`); console.log(packet); break; } bot.emit('custom_playerchat', playerchat.message, playerchat, packet); bot.emit('custom_allchat', playerchat.message, playerchat, packet) }); } const ansiColorCodes = { '§0': '\x1B[30m', '§1': '\x1B[34m', '§2': '\x1B[32m', '§3': '\x1B[36m', '§4': '\x1B[31m', '§5': '\x1B[35m', '§6': '\x1B[33m', '§7': '\x1B[37m', '§8': '\x1B[90m', '§9': '\x1B[94m', '§a': '\x1B[92m', '§b': '\x1B[96m', '§c': '\x1B[91m', '§d': '\x1B[95m', '§e': '\x1B[93m', '§f': '\x1B[97m', 'black': '\x1B[30m', 'dark_blue': '\x1B[34m', 'dark_green': '\x1B[32m', 'dark_aqua': '\x1B[36m', 'dark_red': '\x1B[31m', 'dark_purple': '\x1B[35m', 'gold': '\x1B[33m', 'gray': '\x1B[37m', 'dark_gray': '\x1B[90m', 'blue': '\x1B[94m', 'green': '\x1B[92m', 'aqua': '\x1B[96m', 'red': '\x1B[91m', 'light_purple': '\x1B[95m', 'yellow': '\x1B[93m', 'white': '\x1B[97m' }; const ansiFormatCodes = { '§l': '\x1B[1m', '§o': '\x1B[3m', '§n': '\x1B[4m', '§m': '\x1B[9m', '§k': '\x1B[5m', '§r': '\x1B[0m', 'bold': '\x1B[1m', 'italic': '\x1B[3m', 'underlined': '\x1B[4m', 'strikethrough': '\x1B[9m', 'obfuscated': '\x1B[5m', 'reset': '\x1B[0m', }; function parseMinecraftMessage(component) { if (component === undefined) return; function extractText(comp) { let text = ''; if (comp.text && typeof comp.text === 'string' || typeof comp.text === 'number') { text += comp.text; } if (comp[""] && typeof comp[""] === 'string' || typeof comp[""] === 'number') { text += comp[""]; } if (comp && typeof comp === 'string' || typeof comp === 'number') { return comp; } if (comp.extra) { if (!Array.isArray(comp.extra)) comp.extra = [comp.extra] comp.extra.forEach(subComp => { text += formatfunction(comp, extractText(subComp)); }); } if (comp.translate) { // im cook. let translateString = lang[comp.translate] || comp.translate; let DefaultTranslateString = lang[comp.translate] || comp.translate; let DefaultMsg = false; if (comp.with) { const withArgs = comp.with.map(arg => extractText(arg)); let usedReplacements = 0; translateString = translateString.replace(/%s/g, (match, offset, string) => { if (offset > 0 && string[offset - 1] === '%') { return 's'; } if (usedReplacements < withArgs.length) { const formattedArg = formatfunction(comp, withArgs[usedReplacements]); if (translateString.length + formattedArg.length > 2048) return 'Translate Crash'; usedReplacements++; return formattedArg; } DefaultMsg = true; return "%s"; }); translateString = translateString.replace(/%(\d+)\$s/g, (match, index, stringindex, string) => { const argIndex = parseInt(index) - 1; if (argIndex < 0 || argIndex >= withArgs.length) { DefaultMsg = true; return match; } if (stringindex > 0 && string[stringindex - 1] === '%') { return match; } const formattedArg = formatfunction(comp, withArgs[argIndex]); if (translateString.length + formattedArg.length > 2048) return 'Translate Crash'; return formattedArg; }); } if (DefaultMsg) { text += formatfunction(comp, DefaultTranslateString); } else { text += formatfunction(comp, translateString); } } text = parseMinecraftColor(comp.color) + parseMinecraftFormat(comp) + text + ansiFormatCodes['reset']; return text; } return extractText(component) + ansiFormatCodes['reset']; } function parseMinecraftMessageNoColor(component) { if (component === undefined) return; function extractText(comp) { let text = ''; if (comp.text && typeof comp.text === 'string' || typeof comp.text === 'number') { text += comp.text; } if (comp[""] && typeof comp[""] === 'string' || typeof comp[""] === 'number') { text += comp[""]; } if (comp && typeof comp === 'string' || typeof comp === 'number') { return comp; } if (comp.extra) { if (!Array.isArray(comp.extra)) comp.extra = [comp.extra] comp.extra.forEach(subComp => { text += extractText(subComp); }); } if (comp.translate) { let translateString = lang[comp.translate] || comp.translate; let DefaultTranslateString = lang[comp.translate] || comp.translate; let DefaultMsg = false; if (comp.with) { const withArgs = comp.with.map(arg => extractText(arg)); let usedReplacements = 0; translateString = translateString.replace(/%s/g, (match, offset, string) => { if (offset > 0 && string[offset - 1] === '%') { return 's'; } if (usedReplacements < withArgs.length) { const formattedArg = withArgs[usedReplacements]; if (translateString.length + formattedArg.length > 2048) return 'Translate Crash'; usedReplacements++; return formattedArg; } DefaultMsg = true; return "%s"; }); translateString = translateString.replace(/%(\d+)\$s/g, (match, index, stringindex, string) => { const argIndex = parseInt(index) - 1; if (argIndex < 0 || argIndex >= withArgs.length) { DefaultMsg = true; return match; } if (stringindex > 0 && string[stringindex - 1] === '%') { return match; } const formattedArg = withArgs[argIndex]; if (translateString.length + formattedArg.length > 2048) return 'Translate Crash'; return formattedArg; }); } if (DefaultMsg) { text += DefaultTranslateString; } else { text += translateString; } } return text; } return extractText(component); } function formatfunction(comp, text) { if (text === undefined) return ''; return text = parseMinecraftColor(comp.color) + parseMinecraftFormat(comp) + text + parseMinecraftColor(comp.color) + parseMinecraftFormat(comp); } function parseMinecraftColor(color) { if (color && ansiColorCodes[color] && !color.startsWith('#')) { return ansiColorCodes[color]; } else if (color && color.startsWith('#')) { const hexRegex = /#?([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})/; const hexCodes = hexRegex.exec(color); if (hexCodes) { const red = parseInt(hexCodes[1], 16); const green = parseInt(hexCodes[2], 16); const blue = parseInt(hexCodes[3], 16); const ansiColor = `\u001b[38;2;${red};${green};${blue}m`; return ansiColor; } } else { return ''; } } function parseMinecraftFormat(format) { let result = ''; if (format.bold && format.bold === 1) result += ansiFormatCodes['bold']; if (format.italic && format.italic === 1) result += ansiFormatCodes['italic']; if (format.underlined && format.underlined === 1) result += ansiFormatCodes['underlined']; if (format.strikethrough && format.strikethrough === 1) result += ansiFormatCodes['strikethrough']; if (format.obfuscated && format.obfuscated === 1) result += ansiFormatCodes['obfuscated']; return result; } module.exports = { inject };