Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minecraft 1.20.2 support #3262

Merged
merged 18 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ First time using Node.js? You may want to start with the [tutorial](tutorial.md)

## Features

* Supports Minecraft 1.8 to 1.20.1 (1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19 and 1.20)
* Supports Minecraft 1.8 to 1.20.2 (1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19 and 1.20)
* Entity knowledge and tracking.
* Block knowledge. You can query the world around you. Milliseconds to find any block.
* Physics and movement - handle all bounding boxes
Expand Down
2 changes: 2 additions & 0 deletions examples/anvil_saver/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
engine-strict=true
package-lock=false
2 changes: 2 additions & 0 deletions examples/pathfinder/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
engine-strict=true
package-lock=false
2 changes: 1 addition & 1 deletion examples/pathfinder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.0.0",
"private": true,
"dependencies": {
"mineflayer-pathfinder": "^1.6.1",
"mineflayer-pathfinder": "^2.4.5",
"mineflayer": "file:../../"
},
"description": "A mineflayer example"
Expand Down
2 changes: 2 additions & 0 deletions examples/place_end_crystal/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
engine-strict=true
package-lock=false
2 changes: 2 additions & 0 deletions examples/screenshot-with-node-canvas-webgl/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
engine-strict=true
package-lock=false
2 changes: 2 additions & 0 deletions examples/viewer/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
engine-strict=true
package-lock=false
24 changes: 24 additions & 0 deletions lib/plugins/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,30 @@ function inject (bot, { version, storageBuilder, hideErrors }) {
}
})

// Chunk batches are used by the server to throttle the chunks per tick for players based on their connection speed.
let chunkBatchStartTime = 0
// The Vanilla client uses nano seconds with its weighted average starting at 2000000 converted to milliseconds that is 2
let weightedAverage = 2
// This is used for keeping track of the weight of the old average when updating it.
let oldSampleWeight = 1

bot._client.on('chunk_batch_start', (packet) => {
// Get the time the chunk batch is starting.
chunkBatchStartTime = Date.now()
})

bot._client.on('chunk_batch_finished', (packet) => {
const milliPerChunk = (Date.now() - chunkBatchStartTime) / packet.batchSize
// Prevents the MilliPerChunk from being hugely different then the average, Vanilla uses 3 as a constant here.
const clampedMilliPerChunk = Math.min(Math.max(milliPerChunk, weightedAverage / 3.0), weightedAverage * 3.0)
weightedAverage = ((weightedAverage * oldSampleWeight) + clampedMilliPerChunk) / (oldSampleWeight + 1)
// 49 is used in Vanilla client to limit it to 50 samples
oldSampleWeight = Math.min(49, oldSampleWeight + 1)
bot._client.write('chunk_batch_received', {
// Vanilla uses 7000000 as a constant here, since we are using milliseconds that is now 7. Not sure why they pick this constant to convert from nano seconds per chunk to chunks per tick.
chunksPerTick: 7 / weightedAverage
})
})
bot._client.on('map_chunk', (packet) => {
addColumn({
x: packet.x,
Expand Down
97 changes: 52 additions & 45 deletions lib/plugins/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const entityStatusEvents = {
}

function inject (bot) {
const { mobs, entitiesArray } = bot.registry
const { mobs } = bot.registry
const Entity = require('prismarine-entity')(bot.version)
const Item = require('prismarine-item')(bot.version)
const ChatMessage = require('prismarine-chat')(bot.registry)
Expand Down Expand Up @@ -129,33 +129,6 @@ function inject (bot) {
if (eventName) bot.emit(eventName, entity)
})

bot._client.on('named_entity_spawn', (packet) => {
// in case player_info packet was not sent before named_entity_spawn : ignore named_entity_spawn (see #213)
if (packet.playerUUID in bot.uuidToUsername) {
// spawn named entity
const entity = fetchEntity(packet.entityId)
entity.type = 'player'
entity.name = 'player'
entity.username = bot.uuidToUsername[packet.playerUUID]
entity.uuid = packet.playerUUID
entity.dataBlobs = packet.data
if (bot.supportFeature('fixedPointPosition')) {
entity.position.set(packet.x / 32, packet.y / 32, packet.z / 32)
} else if (bot.supportFeature('doublePosition')) {
entity.position.set(packet.x, packet.y, packet.z)
}
entity.yaw = conv.fromNotchianYawByte(packet.yaw)
entity.pitch = conv.fromNotchianPitchByte(packet.pitch)
entity.height = NAMED_ENTITY_HEIGHT
entity.width = NAMED_ENTITY_WIDTH
entity.metadata = parseMetadata(packet.metadata, entity.metadata)
if (bot.players[entity.username] !== undefined && !bot.players[entity.username].entity) {
bot.players[entity.username].entity = entity
}
bot.emit('entitySpawn', entity)
}
})

bot.on('entityCrouch', (entity) => {
entity.height = CROUCH_HEIGHT
})
Expand All @@ -171,10 +144,11 @@ function inject (bot) {
bot.emit('playerCollect', collector, collected)
})

// What is internalId?
const entityDataByInternalId = Object.fromEntries(bot.registry.entitiesArray.map((e) => [e.internalId, e]))

function setEntityData (entity, type, entityData) {
if (entityData === undefined) {
entityData = entitiesArray.find(entity => entity.internalId === type)
}
entityData ??= entityDataByInternalId[type]
if (entityData) {
entity.type = entityData.type || 'object'
entity.displayName = entityData.displayName
Expand All @@ -193,24 +167,57 @@ function inject (bot) {
}
}

// spawn object/vehicle on versions < 1.19, on versions > 1.19 handles all non-player entities
bot._client.on('spawn_entity', (packet) => {
const entity = fetchEntity(packet.entityId)
const entityData = bot.registry.entities[packet.type]
setEntityData(entity, packet.type, entityData)

function updateEntityPos (entity, pos) {
if (bot.supportFeature('fixedPointPosition')) {
entity.position.set(packet.x / 32, packet.y / 32, packet.z / 32)
entity.position.set(pos.x / 32, pos.y / 32, pos.z / 32)
} else if (bot.supportFeature('doublePosition')) {
entity.position.set(packet.x, packet.y, packet.z)
} else if (bot.supportFeature('consolidatedEntitySpawnPacket')) {
entity.headPitch = conv.fromNotchianPitchByte(packet.headPitch)
entity.position.set(pos.x, pos.y, pos.z)
}
entity.yaw = conv.fromNotchianYawByte(pos.yaw)
entity.pitch = conv.fromNotchianPitchByte(pos.pitch)
}

entity.uuid = packet.objectUUID
entity.yaw = conv.fromNotchianYawByte(packet.yaw)
entity.pitch = conv.fromNotchianPitchByte(packet.pitch)
entity.objectData = packet.objectData
function addNewPlayer (entityId, uuid, pos) {
const entity = fetchEntity(entityId)
entity.type = 'player'
entity.name = 'player'
entity.username = bot.uuidToUsername[uuid]
entity.uuid = uuid
updateEntityPos(entity, pos)
entity.height = NAMED_ENTITY_HEIGHT
entity.width = NAMED_ENTITY_WIDTH
if (bot.players[entity.username] !== undefined && !bot.players[entity.username].entity) {
bot.players[entity.username].entity = entity
}
return entity
}

function addNewNonPlayer (entityId, uuid, entityType, pos) {
const entity = fetchEntity(entityId)
const entityData = bot.registry.entities[entityType]
setEntityData(entity, entityType, entityData)
updateEntityPos(entity, pos)
return entity
}

bot._client.on('named_entity_spawn', (packet) => {
// in case player_info packet was not sent before named_entity_spawn : ignore named_entity_spawn (see #213)
if (packet.playerUUID in bot.uuidToUsername) {
// spawn named entity
const entity = addNewPlayer(packet.entityId, packet.playerUUID, packet, packet.metadata)
entity.dataBlobs = packet.data // this field doesn't appear to be listed on any version
entity.metadata = parseMetadata(packet.metadata, entity.metadata) // 1.8
bot.emit('entitySpawn', entity)
}
})

// spawn object/vehicle on versions < 1.19, on versions > 1.19 handles all non-player entities
// on versions >= 1.20.2, this also handles player entities
bot._client.on('spawn_entity', (packet) => {
const entityData = entityDataByInternalId[packet.type]
const entity = entityData?.type === 'player'
? addNewPlayer(packet.entityId, packet.objectUUID, packet)
: addNewNonPlayer(packet.entityId, packet.objectUUID, packet.type, packet)
bot.emit('entitySpawn', entity)
})

Expand Down
5 changes: 5 additions & 0 deletions lib/plugins/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ function inject (bot, options) {
const brandChannel = getBrandCustomChannelName()
bot._client.registerChannel(brandChannel, ['string', []])

// 1.20.2
bot._client.on('registry_data', (packet) => {
bot.registry.loadDimensionCodec(packet.codec)
})

bot._client.on('login', (packet) => {
handleRespawnPacketData(packet)

Expand Down
4 changes: 3 additions & 1 deletion lib/version.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const testedVersions = ['1.8.8', '1.9.4', '1.10.2', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.5', '1.17.1', '1.18.2', '1.19', '1.19.2', '1.19.3', '1.19.4', '1.20.1']
const testedVersions = ['1.8.8', '1.9.4', '1.10.2', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.5', '1.17.1', '1.18.2', '1.19', '1.19.2', '1.19.3', '1.19.4', '1.20.1', '1.20.2']
module.exports = {

testedVersions,
latestSupportedVersion: testedVersions[testedVersions.length - 1],
oldestSupportedVersion: testedVersions[0]

}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
},
"license": "MIT",
"dependencies": {
"minecraft-data": "^3.44.0",
"minecraft-data": "^3.56.0",
"minecraft-protocol": "^1.44.0",
"prismarine-biome": "^1.1.1",
"prismarine-block": "^1.17.0",
Expand Down
Loading
Loading