import settings from '../settings.js' import parsePlain from '../util/chatparse_plain.js' import parseConsole from '../util/chatparse_console.js' import parse1204 from '../util/parseNBT.js' import { getMessage } from '../util/lang.js' import { readdirSync } from 'node:fs' const convertChatStyleItem = (item) => { const output = {} for (const i in item) { output[i] = item[i].value } return output } const convertChatTypeItem = (item) => { if (item.style) { return { translation_key: item.translation_key.value, parameters: item.parameters.value.value, style: convertChatStyleItem(item.style.value) } } else { return { translation_key: item.translation_key.value, parameters: item.parameters.value.value, style: {} } } } // Level 0: highly specific parsers for certain players // Level 1: server chat format parsers // Level 2: generic parsers const parsers = [[], [], []] const bpl = readdirSync('chatParsers') for (const plugin of bpl) { if (!plugin.endsWith('.js')) { continue } try { import(`../chatParsers/${plugin}`).then((pluginItem) => { parsers[pluginItem.priority].push(pluginItem.parse) }) } catch (e) { console.log(e) } } export default function 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 && data.codec.value['minecraft:chat_type']) { const nbtItems = data.codec.value['minecraft:chat_type'].value.value.value.value nbtItems.forEach((item, i) => { b.messageTypes[i] = convertChatTypeItem(item.element.value.chat.value) }) } else if (data.entries && data.id === 'minecraft:chat_type') { data.entries.forEach((item, i) => { b.messageTypes[i] = convertChatTypeItem(data.entries[i].value.value.chat.value) }) } }) b._client.on('profileless_chat', (data) => { let messageType if (data.type.registryIndex) { messageType = b.messageTypes[data.type.registryIndex - 1] } else { 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') { json.with[i] = parse1204(data.message) } else if (item === 'sender') { json.with[i] = parse1204(data.name) } else if (item === 'target') { json.with[i] = parse1204(data.target) } }) for (const i in messageType.style) { json[i] = messageType.style[i] } 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, playerChatType: messageType }) }) b._client.on('player_chat', (data) => { let messageType if (data.type.registryIndex) { messageType = b.messageTypes[data.type.registryIndex - 1] } else { 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') { if (messageType.translation_key === '%s') { json.with[i] = parse1204(data.unsignedChatContent) } else { json.with[i] = data.plainMessage } } else if (item === 'sender') { json.with[i] = parse1204(data.networkName) } else if (item === 'target' && data.networkTargetName) { json.with[i] = parse1204(data.networkTargetName) } }) for (const i in messageType.style) { json[i] = messageType.style[i] } b.emit('chat_unparsed', { json, type: 'player', uuid: data.senderUuid, message: data.plainMessage, nickname: parsePlain(parse1204(data.networkName)), username: b.findRealNameFromUUID(data.senderUuid), playerChatType: messageType }) }) b._client.on('system_chat', (data) => { const json = parse1204(data.content) b.emit('chat_unparsed', { json, type: 'system', 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) let nickname let username let message let uuid if (data.uuid) uuid = data.uuid b.emit('chat_unparsed', { json, type: 'legacy', uuid, message, nickname, 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, data.subtype) b.displayChat(data.type, data.subtype, `${msgConsole}\x1b[0m`) }) }