UNPKG

minecraft-protocol

Version:

Parse and serialize minecraft packets, plus authentication and encryption.

93 lines (83 loc) 3.46 kB
const states = require('../states') const signedChatPlugin = require('./chat') const uuid = require('uuid-1345') module.exports = function (client, options) { client.serverFeatures = {} client.on('server_data', (packet) => { client.serverFeatures = { chatPreview: packet.previewsChat, enforcesSecureChat: packet.enforcesSecureChat // in LoginPacket v>=1.20.5 } }) client.once('login', (packet) => { if (packet.enforcesSecureChat) client.serverFeatures.enforcesSecureChat = packet.enforcesSecureChat const mcData = require('minecraft-data')(client.version) if (mcData.supportFeature('useChatSessions') && client.profileKeys && client.cipher && client.session.selectedProfile.id === client.uuid.replace(/-/g, '')) { client._session = { index: 0, uuid: uuid.v4fast() } client.write('chat_session_update', { sessionUUID: client._session.uuid, expireTime: client.profileKeys ? BigInt(client.profileKeys.expiresOn.getTime()) : undefined, publicKey: client.profileKeys ? client.profileKeys.public.export({ type: 'spki', format: 'der' }) : undefined, signature: client.profileKeys ? client.profileKeys.signatureV2 : undefined }) } }) client.once('success', onLogin) function onLogin (packet) { const mcData = require('minecraft-data')(client.version) client.uuid = packet.uuid client.username = packet.username if (mcData.supportFeature('hasConfigurationState')) { client.write('login_acknowledged', {}) enterConfigState(onReady) // Server can tell client to re-enter config state client.on('start_configuration', () => enterConfigState()) } else { client.state = states.PLAY onReady() } function enterConfigState (finishCb) { if (client.state === states.CONFIGURATION) return // If we are returning to the configuration state from the play state, we ahve to acknowledge it. if (client.state === states.PLAY) { client.write('configuration_acknowledged', {}) } client.state = states.CONFIGURATION client.once('select_known_packs', () => { client.write('select_known_packs', { packs: [] }) }) // Server should send finish_configuration on its own right after sending the client a dimension codec // for login (that has data about world height, world gen, etc) after getting a login success from client client.once('finish_configuration', () => { client.write('finish_configuration', {}) client.state = states.PLAY finishCb?.() }) } function onReady () { if (mcData.supportFeature('signedChat')) { if (options.disableChatSigning && client.serverFeatures.enforcesSecureChat) { throw new Error('"disableChatSigning" was enabled in client options, but server is enforcing secure chat') } signedChatPlugin(client, options) } else { client.on('chat', (packet) => { client.emit(packet.position === 0 ? 'playerChat' : 'systemChat', { formattedMessage: packet.message, sender: packet.sender, positionId: packet.position, verified: false }) }) } function unsignedChat (message) { client.write('chat', { message }) } client.chat = client._signedChat || unsignedChat client.emit('playerJoin') } } }