122 lines
3.8 KiB
JavaScript
122 lines
3.8 KiB
JavaScript
const nbt = require('prismarine-nbt')
|
|
module.exports = inject
|
|
|
|
const difficultyNames = ['peaceful', 'easy', 'normal', 'hard']
|
|
const gameModes = ['survival', 'creative', 'adventure', 'spectator']
|
|
|
|
const dimensionNames = {
|
|
'-1': 'the_nether',
|
|
0: 'overworld',
|
|
1: 'the_end'
|
|
}
|
|
|
|
const parseGameMode = gameModeBits => gameModes[(gameModeBits & 0b11)] // lower two bits
|
|
|
|
function inject (bot, options) {
|
|
function getBrandCustomChannelName () {
|
|
if (bot.supportFeature('customChannelMCPrefixed')) {
|
|
return 'MC|Brand'
|
|
} else if (bot.supportFeature('customChannelIdentifier')) {
|
|
return 'minecraft:brand'
|
|
}
|
|
throw new Error('Unsupported brand channel name')
|
|
}
|
|
|
|
function handleRespawnPacketData (packet) {
|
|
bot.game.levelType = packet.levelType ?? (packet.isFlat ? 'flat' : 'default')
|
|
bot.game.hardcore = packet.isHardcore ?? Boolean(packet.gameMode & 0b100)
|
|
bot.game.gameMode = parseGameMode(packet.gameMode)
|
|
if (bot.supportFeature('dimensionIsAnInt')) {
|
|
bot.game.dimension = dimensionNames[packet.dimension]
|
|
} else if (bot.supportFeature('dimensionIsAString')) {
|
|
bot.game.dimension = packet.dimension.replace('minecraft:', '')
|
|
} else if (bot.supportFeature('dimensionIsAWorld')) {
|
|
bot.game.dimension = packet.worldName.replace('minecraft:', '')
|
|
} else {
|
|
throw new Error('Unsupported dimension type in login packet')
|
|
}
|
|
|
|
if (packet.dimensionCodec) {
|
|
bot.registry.loadDimensionCodec(packet.dimensionCodec)
|
|
}
|
|
|
|
if (bot.supportFeature('dimensionDataInCodec')) { // 1.19+
|
|
if (packet.worldType) { // login
|
|
bot.game.dimension = packet.worldType.replace('minecraft:', '')
|
|
const { minY, height } = bot.registry.dimensionsByName[bot.game.dimension]
|
|
bot.game.minY = minY
|
|
bot.game.height = height
|
|
} else if (packet.dimension) { // respawn
|
|
bot.game.dimension = packet.dimension.replace('minecraft:', '')
|
|
const { minY, height } = bot.registry.dimensionsByName[bot.game.dimension]
|
|
bot.game.minY = minY
|
|
bot.game.height = height
|
|
}
|
|
} else if (bot.supportFeature('dimensionDataIsAvailable')) { // 1.18
|
|
const dimensionData = nbt.simplify(packet.dimension)
|
|
bot.game.minY = dimensionData.min_y
|
|
bot.game.height = dimensionData.height
|
|
} else {
|
|
bot.game.minY = 0
|
|
bot.game.height = 256
|
|
}
|
|
|
|
if (packet.difficulty) {
|
|
bot.game.difficulty = difficultyNames[packet.difficulty]
|
|
}
|
|
}
|
|
|
|
bot.game = {}
|
|
|
|
const brandChannel = getBrandCustomChannelName()
|
|
bot._client.registerChannel(brandChannel, ['string', []])
|
|
|
|
bot._client.on('login', (packet) => {
|
|
handleRespawnPacketData(packet)
|
|
|
|
bot.game.maxPlayers = packet.maxPlayers
|
|
if (packet.enableRespawnScreen) {
|
|
bot.game.enableRespawnScreen = packet.enableRespawnScreen
|
|
}
|
|
if (packet.viewDistance) {
|
|
bot.game.serverViewDistance = packet.viewDistance
|
|
}
|
|
|
|
bot.emit('login')
|
|
bot.emit('game')
|
|
|
|
// varint length-prefixed string as data
|
|
bot._client.writeChannel(brandChannel, options.brand)
|
|
})
|
|
|
|
bot._client.on('respawn', (packet) => {
|
|
handleRespawnPacketData(packet)
|
|
bot.emit('game')
|
|
})
|
|
|
|
bot._client.on('game_state_change', (packet) => {
|
|
if (packet?.reason === 4 && packet?.gameMode === 1) {
|
|
bot._client.write('client_command', { action: 0 })
|
|
}
|
|
if (packet.reason === 3) {
|
|
bot.game.gameMode = parseGameMode(packet.gameMode)
|
|
bot.emit('game')
|
|
}
|
|
})
|
|
|
|
bot._client.on('difficulty', (packet) => {
|
|
bot.game.difficulty = difficultyNames[packet.difficulty]
|
|
})
|
|
|
|
bot._client.on(brandChannel, (serverBrand) => {
|
|
bot.game.serverBrand = serverBrand
|
|
})
|
|
|
|
// mimic the vanilla 1.17 client to prevent anticheat kicks
|
|
bot._client.on('ping', (data) => {
|
|
bot._client.write('pong', {
|
|
id: data.id
|
|
})
|
|
})
|
|
}
|