Skip to content

Commit

Permalink
1.20.6 (#3412)
Browse files Browse the repository at this point in the history
* 1.20.5

* lint

* fix

* update registry

* update java

* add debug

* fix

* debug

* Update testCommon.js

* update ci

* add protodef AOT compile code

* Update protodefCompile.js

* Update testCommon.js

* pitem, fix `login` event

* debug

* Update testCommon.js

* Update package.json test

* Update package.json

* update test events

* Update testCommon.js

* update

* fix pitem source

* remove some debug logging

* update

* Fix trade test

* remove manual protodef install from ci

* remove unnecessary install in ci

* change back version.js to support latest version

* update deps

* remove compile protocol in ci

* bump to support 1.20.6

* in tests teleport to overworld to prevent nether test to break the environment

* fix respawn in internal tests

* use normal tp before 1.14

* lint

* fix held item test

* fix item drop internal test for 1.20.6

* cleanup

---------

Co-authored-by: Romain Beaumont <romain.rom1@gmail.com>
  • Loading branch information
extremeheat and rom1504 authored Oct 13, 2024
1 parent 1c2a5c0 commit 44fad41
Show file tree
Hide file tree
Showing 22 changed files with 184 additions and 81 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
- name: Setup Java JDK
uses: actions/setup-java@v1.4.3
with:
java-version: 17
java-version: 21
java-package: jre
- name: Install Dependencies
run: npm install
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ test/server_*
.vscode
.DS_Store
launcher_accounts.json
data
2 changes: 1 addition & 1 deletion .gitpod.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
tasks:
- command: npm install
- command: npm install && sdk install java
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.4 (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.5 (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 upto 1.20.6)
* 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
1 change: 1 addition & 0 deletions lib/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ function createBot (options = {}) {
}).map(key => options.plugins[key])
bot.loadPlugins([...internalPlugins, ...externalPlugins])

options.validateChannelProtocol = false
bot._client = bot._client ?? mc.createClient(options)
bot._client.on('connect', () => {
bot.emit('connect')
Expand Down
30 changes: 21 additions & 9 deletions lib/particle.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ module.exports = loader
function loader (registry) {
class Particle {
constructor (id, position, offset, count = 1, movementSpeed = 0, longDistanceRender = false) {
Object.assign(this, registry.particles[id])
this.id = id
Object.assign(this, registry.particles[id] || registry.particlesByName[id])
this.position = position
this.offset = offset
this.count = count
Expand All @@ -15,14 +15,26 @@ function loader (registry) {
}

static fromNetwork (packet) {
return new Particle(
packet.particleId,
new Vec3(packet.x, packet.y, packet.z),
new Vec3(packet.offsetX, packet.offsetY, packet.offsetZ),
packet.particles,
packet.particleData,
packet.longDistance
)
if (registry.supportFeature('updatedParticlesPacket')) {
// TODO: We add extra data that's inside packet.particle.data that varies by the particle's .type
return new Particle(
packet.particle.type,
new Vec3(packet.x, packet.y, packet.z),
new Vec3(packet.offsetX, packet.offsetY, packet.offsetZ),
packet.amount,
packet.velocityOffset,
packet.longDistance
)
} else {
return new Particle(
packet.particleId,
new Vec3(packet.x, packet.y, packet.z),
new Vec3(packet.offsetX, packet.offsetY, packet.offsetZ),
packet.particles,
packet.particleData,
packet.longDistance
)
}
}
}

Expand Down
8 changes: 8 additions & 0 deletions lib/plugins/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,9 @@ function inject (bot, { version, storageBuilder, hideErrors }) {
if (bot.supportFeature('dimensionIsAnInt')) {
dimension = packet.dimension
worldName = dimensionToFolderName(dimension)
} else if (bot.supportFeature('spawnRespawnWorldDataField')) { // 1.20.5+
dimension = packet.worldState.dimension
worldName = packet.worldState.name
} else {
dimension = packet.dimension
worldName = /^minecraft:.+/.test(packet.worldName) ? packet.worldName : `minecraft:${packet.worldName}`
Expand All @@ -542,6 +545,11 @@ function inject (bot, { version, storageBuilder, hideErrors }) {
if (bot.supportFeature('dimensionIsAnInt')) { // <=1.15.2
if (dimension === packet.dimension) return
dimension = packet.dimension
} else if (bot.supportFeature('spawnRespawnWorldDataField')) { // 1.20.5+
if (dimension === packet.worldState.dimension) return
if (worldName === packet.worldState.name && packet.copyMetadata === true) return // don't unload chunks if in same world and metaData is true
dimension = packet.worldState.dimension
worldName = packet.worldState.name
} else { // >= 1.15.2
if (dimension === packet.dimension) return
if (worldName === packet.worldName && packet.copyMetadata === true) return // don't unload chunks if in same world and metaData is true
Expand Down
22 changes: 12 additions & 10 deletions lib/plugins/breath.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
module.exports = inject

function inject (bot) {
if (bot.supportFeature('mcDataHasEntityMetadata')) {
// this is handled inside entities.js. We don't yet have entity metadataKeys for all versions but once we do
// we can delete the numerical checks here and in entities.js https://github.com/extremeheat/mineflayer/blob/eb9982aa04973b0086aac68a2847005d77f01a3d/lib/plugins/entities.js#L469
return
}
bot._client.on('entity_metadata', (packet) => {
if (!bot?.entity?.id === packet?.entityId) return
if (packet?.metadata[1]?.key === 1) {
if (!packet?.metadata[1]?.value) return
bot.oxygenLevel = Math.round(packet.metadata[1].value / 15)
bot.emit('breath')
}
if (packet?.metadata[0]?.key === 1) {
if (!packet?.metadata[0]?.value) return
bot.oxygenLevel = Math.round(packet.metadata[0].value / 15)
bot.emit('breath')
if (!bot.entity) return
if (bot.entity.id !== packet.entityId) return
for (const metadata of packet.metadata) {
if (metadata.key === 1) {
bot.oxygenLevel = Math.round(packet.metadata[1].value / 15)
bot.emit('breath')
}
}
})
}
5 changes: 4 additions & 1 deletion lib/plugins/creative.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ function inject (bot) {
item: Item.toNotch(item)
})

await onceWithCleanup(bot.inventory, `updateSlot:${slot}`, { checkCondition: (oldItem, newItem) => item === null ? newItem === null : newItem?.name === item.name && newItem?.count === item.count && newItem?.metadata === item.metadata })
await onceWithCleanup(bot.inventory, `updateSlot:${slot}`, {
timeout: 5000,
checkCondition: (oldItem, newItem) => item === null ? newItem === null : newItem?.name === item.name && newItem?.count === item.count && newItem?.metadata === item.metadata
})
creativeSlotsUpdates[slot] = false
}

Expand Down
6 changes: 6 additions & 0 deletions lib/plugins/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,12 @@ function inject (bot) {
bot.emit('entityUncrouch', entity)
}
}

// Breathing (formerly in breath.js)
if (metas.air_supply != null) {
bot.oxygenLevel = Math.round(metas.air_supply / 15)
bot.emit('breath')
}
} else {
const typeSlot = (bot.supportFeature('itemsAreAlsoBlocks') ? 5 : 6) + (bot.supportFeature('entityMetadataHasLong') ? 1 : 0)
const slot = packet.metadata.find(e => e.type === typeSlot)
Expand Down
9 changes: 7 additions & 2 deletions lib/plugins/fishing.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ function inject (bot) {
if (!lastBobber || fishingTask.done) return

const pos = lastBobber.position
const parts = bot.registry.particlesByName
if (packet.particleId === (parts?.fishing ?? parts.bubble).id && packet.particles === 6 && pos.distanceTo(new Vec3(packet.x, pos.y, packet.z)) <= 1.23) {

const bobberCondition = bot.registry.supportFeature('updatedParticlesPacket')
? ((packet.particle.type === 'fishing' || packet.particle.type === 'bubble') && packet.amount === 6 && pos.distanceTo(new Vec3(packet.x, pos.y, packet.z)) <= 1.23)
// This "(particles.fishing ?? particles.bubble).id" condition doesn't make sense (these are both valid types)
: (packet.particleId === (bot.registry.particlesByName.fishing ?? bot.registry.particlesByName.bubble).id && packet.particles === 6 && pos.distanceTo(new Vec3(packet.x, pos.y, packet.z)) <= 1.23)

if (bobberCondition) {
bot.activateItem()
lastBobber = undefined
fishingTask.finish()
Expand Down
42 changes: 25 additions & 17 deletions lib/plugins/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@ function inject (bot, options) {
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.gameMode = packet.gamemode || parseGameMode(packet.gameMode)
if (bot.supportFeature('segmentedRegistryCodecData')) { // 1.20.5
if (typeof packet.dimension === 'number') {
bot.game.dimension = bot.registry.dimensionsArray[packet.dimension]?.name?.replace('minecraft:', '')
} else if (typeof packet.dimension === 'string') { // iirc, in 1.21 it's back to a string
bot.game.dimension = packet.dimension.replace('minecraft:', '')
}
} else if (bot.supportFeature('dimensionIsAnInt')) {
bot.game.dimension = dimensionNames[packet.dimension]
} else if (bot.supportFeature('dimensionIsAString')) {
bot.game.dimension = packet.dimension.replace('minecraft:', '')
Expand All @@ -40,25 +46,25 @@ function inject (bot, options) {
bot.registry.loadDimensionCodec(packet.dimensionCodec)
}

bot.game.minY = 0
bot.game.height = 256

if (bot.supportFeature('dimensionDataInCodec')) { // 1.19+
if (packet.worldType) { // login
// pre 1.20.5 before we consolidated login and respawn's SpawnInfo structure into one type,
// "dimension" was called "worldType" in login_packet's payload but not respawn.
if (packet.worldType && !bot.game.dimension) {
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
}
console.log('*Dimension data', bot.game.dimension, bot.registry.dimensionsByName, packet)
const dimData = bot.registry.dimensionsByName[bot.game.dimension]
if (dimData) {
bot.game.minY = dimData.minY
bot.game.height = dimData.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) {
Expand All @@ -73,11 +79,12 @@ function inject (bot, options) {

// 1.20.2
bot._client.on('registry_data', (packet) => {
bot.registry.loadDimensionCodec(packet.codec)
console.log('Loading Dimension Codec', JSON.stringify(packet).slice(0, 100))
bot.registry.loadDimensionCodec(packet.codec || packet)
})

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

bot.game.maxPlayers = packet.maxPlayers
if (packet.enableRespawnScreen) {
Expand All @@ -95,7 +102,8 @@ function inject (bot, options) {
})

bot._client.on('respawn', (packet) => {
handleRespawnPacketData(packet)
// in 1.20.5+ protocol we move the shared spawn data into one SpawnInfo type under .worldState
handleRespawnPacketData(packet.worldState || packet)
bot.emit('game')
})

Expand Down
2 changes: 1 addition & 1 deletion lib/version.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
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', '1.20.4']
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', '1.20.4', '1.20.6']
module.exports = {

testedVersions,
Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"main": "index.js",
"types": "index.d.ts",
"scripts": {
"mocha_test": "mocha --reporter spec --exit",
"mocha_test": "mocha --reporter spec --exit --bail",
"test": "npm run mocha_test",
"pretest": "npm run lint",
"lint": "standard && standard-markdown",
Expand All @@ -21,21 +21,21 @@
},
"license": "MIT",
"dependencies": {
"minecraft-data": "^3.56.0",
"minecraft-protocol": "^1.47.0",
"minecraft-data": "^3.76.0",
"minecraft-protocol": "^1.49.0",
"prismarine-biome": "^1.1.1",
"prismarine-block": "^1.17.0",
"prismarine-chat": "^1.7.1",
"prismarine-chunk": "^1.34.0",
"prismarine-entity": "^2.3.0",
"prismarine-item": "^1.14.0",
"prismarine-item": "^1.15.0",
"prismarine-nbt": "^2.0.0",
"prismarine-physics": "^1.8.0",
"prismarine-recipe": "^1.3.0",
"prismarine-registry": "^1.5.0",
"prismarine-registry": "^1.8.0",
"prismarine-windows": "^2.9.0",
"prismarine-world": "^3.6.0",
"protodef": "^1.14.0",
"protodef": "1.17.0",
"typed-emitter": "^1.0.0",
"vec3": "^0.1.7"
},
Expand All @@ -45,6 +45,7 @@
"minecraft-wrap": "^1.3.0",
"mineflayer": "file:.",
"mocha": "^10.0.0",
"protodef-yaml": "^1.5.3",
"standard": "^17.0.0",
"standard-markdown": "^7.1.0",
"typescript": "^5.4.5"
Expand Down
2 changes: 1 addition & 1 deletion test/externalTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ for (const supportedVersion of mineflayer.testedVersions) {
const runTest = (testName, testFunction) => {
return function (done) {
this.timeout(TEST_TIMEOUT_MS)
bot.test.sayEverywhere(`starting ${testName}`)
bot.test.sayEverywhere(`### Starting ${testName}`)
testFunction(bot, done).then(res => done()).catch(e => done(e))
}
}
Expand Down
1 change: 1 addition & 0 deletions test/externalTests/heldItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = () => async (bot) => {

await bot.test.becomeCreative()
await bot.test.clearInventory()
await bot.test.wait(100)
assert.equal(bot.heldItem, null)

const stoneId = bot.registry.itemsByName.stone.id
Expand Down
4 changes: 3 additions & 1 deletion test/externalTests/nether.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ module.exports = () => async (bot) => {

const p = new Promise((resolve, reject) => {
bot._client.on('open_sign_entity', (packet) => {
console.log('Open sign', packet)
const sign = bot.blockAt(new Vec3(packet.location))
bot.updateSign(sign, '1\n2\n3\n')

setTimeout(() => {
// Get updated sign
const sign = bot.blockAt(bot.entity.position)
console.log('Updated sign', sign)

assert.strictEqual(sign.signText.trimEnd(), '1\n2\n3')

Expand Down Expand Up @@ -48,5 +50,5 @@ module.exports = () => async (bot) => {
await bot.lookAt(lowerBlock.position, true)
await bot.test.setInventorySlot(36, new Item(signItem.id, 1, 0))
await bot.placeBlock(lowerBlock, new Vec3(0, 1, 0))
return p
await p
}
6 changes: 5 additions & 1 deletion test/externalTests/particles.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ module.exports = () => async (bot) => {

return new Promise((resolve, reject) => {
function onParticleEvent (particle) {
assert.strictEqual(particle.id, particleData.id)
if (typeof particle.id === 'number') {
assert.strictEqual(particle.id, particleData.id)
} else {
assert.strictEqual(particle.id, particleData.name)
}
assert.strictEqual(particle.name, particleData.name)
assert.strictEqual(particle.position.x, bot.entity.position.x)
assert.strictEqual(particle.position.y, bot.entity.position.y)
Expand Down
Loading

0 comments on commit 44fad41

Please sign in to comment.