Skip to content

Commit 44fad41

Browse files
extremeheatrom1504
andauthored
* 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 <[email protected]>
1 parent 1c2a5c0 commit 44fad41

22 files changed

+184
-81
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
- name: Setup Java JDK
5353
uses: actions/[email protected]
5454
with:
55-
java-version: 17
55+
java-version: 21
5656
java-package: jre
5757
- name: Install Dependencies
5858
run: npm install

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ test/server_*
1010
.vscode
1111
.DS_Store
1212
launcher_accounts.json
13+
data

.gitpod.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
tasks:
2-
- command: npm install
2+
- command: npm install && sdk install java

docs/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ First time using Node.js? You may want to start with the [tutorial](tutorial.md)
1717

1818
## Features
1919

20-
* 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)
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)
2121
* Entity knowledge and tracking.
2222
* Block knowledge. You can query the world around you. Milliseconds to find any block.
2323
* Physics and movement - handle all bounding boxes

lib/loader.js

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ function createBot (options = {}) {
9595
}).map(key => options.plugins[key])
9696
bot.loadPlugins([...internalPlugins, ...externalPlugins])
9797

98+
options.validateChannelProtocol = false
9899
bot._client = bot._client ?? mc.createClient(options)
99100
bot._client.on('connect', () => {
100101
bot.emit('connect')

lib/particle.js

+21-9
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ module.exports = loader
55
function loader (registry) {
66
class Particle {
77
constructor (id, position, offset, count = 1, movementSpeed = 0, longDistanceRender = false) {
8-
Object.assign(this, registry.particles[id])
98
this.id = id
9+
Object.assign(this, registry.particles[id] || registry.particlesByName[id])
1010
this.position = position
1111
this.offset = offset
1212
this.count = count
@@ -15,14 +15,26 @@ function loader (registry) {
1515
}
1616

1717
static fromNetwork (packet) {
18-
return new Particle(
19-
packet.particleId,
20-
new Vec3(packet.x, packet.y, packet.z),
21-
new Vec3(packet.offsetX, packet.offsetY, packet.offsetZ),
22-
packet.particles,
23-
packet.particleData,
24-
packet.longDistance
25-
)
18+
if (registry.supportFeature('updatedParticlesPacket')) {
19+
// TODO: We add extra data that's inside packet.particle.data that varies by the particle's .type
20+
return new Particle(
21+
packet.particle.type,
22+
new Vec3(packet.x, packet.y, packet.z),
23+
new Vec3(packet.offsetX, packet.offsetY, packet.offsetZ),
24+
packet.amount,
25+
packet.velocityOffset,
26+
packet.longDistance
27+
)
28+
} else {
29+
return new Particle(
30+
packet.particleId,
31+
new Vec3(packet.x, packet.y, packet.z),
32+
new Vec3(packet.offsetX, packet.offsetY, packet.offsetZ),
33+
packet.particles,
34+
packet.particleData,
35+
packet.longDistance
36+
)
37+
}
2638
}
2739
}
2840

lib/plugins/blocks.js

+8
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,9 @@ function inject (bot, { version, storageBuilder, hideErrors }) {
531531
if (bot.supportFeature('dimensionIsAnInt')) {
532532
dimension = packet.dimension
533533
worldName = dimensionToFolderName(dimension)
534+
} else if (bot.supportFeature('spawnRespawnWorldDataField')) { // 1.20.5+
535+
dimension = packet.worldState.dimension
536+
worldName = packet.worldState.name
534537
} else {
535538
dimension = packet.dimension
536539
worldName = /^minecraft:.+/.test(packet.worldName) ? packet.worldName : `minecraft:${packet.worldName}`
@@ -542,6 +545,11 @@ function inject (bot, { version, storageBuilder, hideErrors }) {
542545
if (bot.supportFeature('dimensionIsAnInt')) { // <=1.15.2
543546
if (dimension === packet.dimension) return
544547
dimension = packet.dimension
548+
} else if (bot.supportFeature('spawnRespawnWorldDataField')) { // 1.20.5+
549+
if (dimension === packet.worldState.dimension) return
550+
if (worldName === packet.worldState.name && packet.copyMetadata === true) return // don't unload chunks if in same world and metaData is true
551+
dimension = packet.worldState.dimension
552+
worldName = packet.worldState.name
545553
} else { // >= 1.15.2
546554
if (dimension === packet.dimension) return
547555
if (worldName === packet.worldName && packet.copyMetadata === true) return // don't unload chunks if in same world and metaData is true

lib/plugins/breath.js

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
module.exports = inject
22

33
function inject (bot) {
4+
if (bot.supportFeature('mcDataHasEntityMetadata')) {
5+
// this is handled inside entities.js. We don't yet have entity metadataKeys for all versions but once we do
6+
// we can delete the numerical checks here and in entities.js https://github.com/extremeheat/mineflayer/blob/eb9982aa04973b0086aac68a2847005d77f01a3d/lib/plugins/entities.js#L469
7+
return
8+
}
49
bot._client.on('entity_metadata', (packet) => {
5-
if (!bot?.entity?.id === packet?.entityId) return
6-
if (packet?.metadata[1]?.key === 1) {
7-
if (!packet?.metadata[1]?.value) return
8-
bot.oxygenLevel = Math.round(packet.metadata[1].value / 15)
9-
bot.emit('breath')
10-
}
11-
if (packet?.metadata[0]?.key === 1) {
12-
if (!packet?.metadata[0]?.value) return
13-
bot.oxygenLevel = Math.round(packet.metadata[0].value / 15)
14-
bot.emit('breath')
10+
if (!bot.entity) return
11+
if (bot.entity.id !== packet.entityId) return
12+
for (const metadata of packet.metadata) {
13+
if (metadata.key === 1) {
14+
bot.oxygenLevel = Math.round(packet.metadata[1].value / 15)
15+
bot.emit('breath')
16+
}
1517
}
1618
})
1719
}

lib/plugins/creative.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ function inject (bot) {
3535
item: Item.toNotch(item)
3636
})
3737

38-
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 })
38+
await onceWithCleanup(bot.inventory, `updateSlot:${slot}`, {
39+
timeout: 5000,
40+
checkCondition: (oldItem, newItem) => item === null ? newItem === null : newItem?.name === item.name && newItem?.count === item.count && newItem?.metadata === item.metadata
41+
})
3942
creativeSlotsUpdates[slot] = false
4043
}
4144

lib/plugins/entities.js

+6
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,12 @@ function inject (bot) {
470470
bot.emit('entityUncrouch', entity)
471471
}
472472
}
473+
474+
// Breathing (formerly in breath.js)
475+
if (metas.air_supply != null) {
476+
bot.oxygenLevel = Math.round(metas.air_supply / 15)
477+
bot.emit('breath')
478+
}
473479
} else {
474480
const typeSlot = (bot.supportFeature('itemsAreAlsoBlocks') ? 5 : 6) + (bot.supportFeature('entityMetadataHasLong') ? 1 : 0)
475481
const slot = packet.metadata.find(e => e.type === typeSlot)

lib/plugins/fishing.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,13 @@ function inject (bot) {
2525
if (!lastBobber || fishingTask.done) return
2626

2727
const pos = lastBobber.position
28-
const parts = bot.registry.particlesByName
29-
if (packet.particleId === (parts?.fishing ?? parts.bubble).id && packet.particles === 6 && pos.distanceTo(new Vec3(packet.x, pos.y, packet.z)) <= 1.23) {
28+
29+
const bobberCondition = bot.registry.supportFeature('updatedParticlesPacket')
30+
? ((packet.particle.type === 'fishing' || packet.particle.type === 'bubble') && packet.amount === 6 && pos.distanceTo(new Vec3(packet.x, pos.y, packet.z)) <= 1.23)
31+
// This "(particles.fishing ?? particles.bubble).id" condition doesn't make sense (these are both valid types)
32+
: (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)
33+
34+
if (bobberCondition) {
3035
bot.activateItem()
3136
lastBobber = undefined
3237
fishingTask.finish()

lib/plugins/game.js

+25-17
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@ function inject (bot, options) {
2525
function handleRespawnPacketData (packet) {
2626
bot.game.levelType = packet.levelType ?? (packet.isFlat ? 'flat' : 'default')
2727
bot.game.hardcore = packet.isHardcore ?? Boolean(packet.gameMode & 0b100)
28-
bot.game.gameMode = parseGameMode(packet.gameMode)
29-
if (bot.supportFeature('dimensionIsAnInt')) {
28+
bot.game.gameMode = packet.gamemode || parseGameMode(packet.gameMode)
29+
if (bot.supportFeature('segmentedRegistryCodecData')) { // 1.20.5
30+
if (typeof packet.dimension === 'number') {
31+
bot.game.dimension = bot.registry.dimensionsArray[packet.dimension]?.name?.replace('minecraft:', '')
32+
} else if (typeof packet.dimension === 'string') { // iirc, in 1.21 it's back to a string
33+
bot.game.dimension = packet.dimension.replace('minecraft:', '')
34+
}
35+
} else if (bot.supportFeature('dimensionIsAnInt')) {
3036
bot.game.dimension = dimensionNames[packet.dimension]
3137
} else if (bot.supportFeature('dimensionIsAString')) {
3238
bot.game.dimension = packet.dimension.replace('minecraft:', '')
@@ -40,25 +46,25 @@ function inject (bot, options) {
4046
bot.registry.loadDimensionCodec(packet.dimensionCodec)
4147
}
4248

49+
bot.game.minY = 0
50+
bot.game.height = 256
51+
4352
if (bot.supportFeature('dimensionDataInCodec')) { // 1.19+
44-
if (packet.worldType) { // login
53+
// pre 1.20.5 before we consolidated login and respawn's SpawnInfo structure into one type,
54+
// "dimension" was called "worldType" in login_packet's payload but not respawn.
55+
if (packet.worldType && !bot.game.dimension) {
4556
bot.game.dimension = packet.worldType.replace('minecraft:', '')
46-
const { minY, height } = bot.registry.dimensionsByName[bot.game.dimension]
47-
bot.game.minY = minY
48-
bot.game.height = height
49-
} else if (packet.dimension) { // respawn
50-
bot.game.dimension = packet.dimension.replace('minecraft:', '')
51-
const { minY, height } = bot.registry.dimensionsByName[bot.game.dimension]
52-
bot.game.minY = minY
53-
bot.game.height = height
57+
}
58+
console.log('*Dimension data', bot.game.dimension, bot.registry.dimensionsByName, packet)
59+
const dimData = bot.registry.dimensionsByName[bot.game.dimension]
60+
if (dimData) {
61+
bot.game.minY = dimData.minY
62+
bot.game.height = dimData.height
5463
}
5564
} else if (bot.supportFeature('dimensionDataIsAvailable')) { // 1.18
5665
const dimensionData = nbt.simplify(packet.dimension)
5766
bot.game.minY = dimensionData.min_y
5867
bot.game.height = dimensionData.height
59-
} else {
60-
bot.game.minY = 0
61-
bot.game.height = 256
6268
}
6369

6470
if (packet.difficulty) {
@@ -73,11 +79,12 @@ function inject (bot, options) {
7379

7480
// 1.20.2
7581
bot._client.on('registry_data', (packet) => {
76-
bot.registry.loadDimensionCodec(packet.codec)
82+
console.log('Loading Dimension Codec', JSON.stringify(packet).slice(0, 100))
83+
bot.registry.loadDimensionCodec(packet.codec || packet)
7784
})
7885

7986
bot._client.on('login', (packet) => {
80-
handleRespawnPacketData(packet)
87+
handleRespawnPacketData(packet.worldState || packet)
8188

8289
bot.game.maxPlayers = packet.maxPlayers
8390
if (packet.enableRespawnScreen) {
@@ -95,7 +102,8 @@ function inject (bot, options) {
95102
})
96103

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

lib/version.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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', '1.20.4']
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', '1.20.4', '1.20.6']
22
module.exports = {
33

44
testedVersions,

package.json

+7-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"main": "index.js",
66
"types": "index.d.ts",
77
"scripts": {
8-
"mocha_test": "mocha --reporter spec --exit",
8+
"mocha_test": "mocha --reporter spec --exit --bail",
99
"test": "npm run mocha_test",
1010
"pretest": "npm run lint",
1111
"lint": "standard && standard-markdown",
@@ -21,21 +21,21 @@
2121
},
2222
"license": "MIT",
2323
"dependencies": {
24-
"minecraft-data": "^3.56.0",
25-
"minecraft-protocol": "^1.47.0",
24+
"minecraft-data": "^3.76.0",
25+
"minecraft-protocol": "^1.49.0",
2626
"prismarine-biome": "^1.1.1",
2727
"prismarine-block": "^1.17.0",
2828
"prismarine-chat": "^1.7.1",
2929
"prismarine-chunk": "^1.34.0",
3030
"prismarine-entity": "^2.3.0",
31-
"prismarine-item": "^1.14.0",
31+
"prismarine-item": "^1.15.0",
3232
"prismarine-nbt": "^2.0.0",
3333
"prismarine-physics": "^1.8.0",
3434
"prismarine-recipe": "^1.3.0",
35-
"prismarine-registry": "^1.5.0",
35+
"prismarine-registry": "^1.8.0",
3636
"prismarine-windows": "^2.9.0",
3737
"prismarine-world": "^3.6.0",
38-
"protodef": "^1.14.0",
38+
"protodef": "1.17.0",
3939
"typed-emitter": "^1.0.0",
4040
"vec3": "^0.1.7"
4141
},
@@ -45,6 +45,7 @@
4545
"minecraft-wrap": "^1.3.0",
4646
"mineflayer": "file:.",
4747
"mocha": "^10.0.0",
48+
"protodef-yaml": "^1.5.3",
4849
"standard": "^17.0.0",
4950
"standard-markdown": "^7.1.0",
5051
"typescript": "^5.4.5"

test/externalTest.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ for (const supportedVersion of mineflayer.testedVersions) {
132132
const runTest = (testName, testFunction) => {
133133
return function (done) {
134134
this.timeout(TEST_TIMEOUT_MS)
135-
bot.test.sayEverywhere(`starting ${testName}`)
135+
bot.test.sayEverywhere(`### Starting ${testName}`)
136136
testFunction(bot, done).then(res => done()).catch(e => done(e))
137137
}
138138
}

test/externalTests/heldItem.js

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module.exports = () => async (bot) => {
55

66
await bot.test.becomeCreative()
77
await bot.test.clearInventory()
8+
await bot.test.wait(100)
89
assert.equal(bot.heldItem, null)
910

1011
const stoneId = bot.registry.itemsByName.stone.id

test/externalTests/nether.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ module.exports = () => async (bot) => {
1414

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

2021
setTimeout(() => {
2122
// Get updated sign
2223
const sign = bot.blockAt(bot.entity.position)
24+
console.log('Updated sign', sign)
2325

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

@@ -48,5 +50,5 @@ module.exports = () => async (bot) => {
4850
await bot.lookAt(lowerBlock.position, true)
4951
await bot.test.setInventorySlot(36, new Item(signItem.id, 1, 0))
5052
await bot.placeBlock(lowerBlock, new Vec3(0, 1, 0))
51-
return p
53+
await p
5254
}

test/externalTests/particles.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ module.exports = () => async (bot) => {
55

66
return new Promise((resolve, reject) => {
77
function onParticleEvent (particle) {
8-
assert.strictEqual(particle.id, particleData.id)
8+
if (typeof particle.id === 'number') {
9+
assert.strictEqual(particle.id, particleData.id)
10+
} else {
11+
assert.strictEqual(particle.id, particleData.name)
12+
}
913
assert.strictEqual(particle.name, particleData.name)
1014
assert.strictEqual(particle.position.x, bot.entity.position.x)
1115
assert.strictEqual(particle.position.y, bot.entity.position.y)

0 commit comments

Comments
 (0)