mineflayer 4.36.0 → 4.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,15 +32,21 @@ jobs:
32
32
  - id: set-matrix
33
33
  run: |
34
34
  node -e "
35
- const testedVersions = require('./lib/version').testedVersions;
36
- console.log('matrix='+JSON.stringify({'include': testedVersions.map(mcVersion => ({mcVersion}))}))
35
+ const v = require('./lib/version').testedVersions;
36
+ const groups = [];
37
+ const SIZE = 4;
38
+ for (let i = 0; i < v.length; i += SIZE) {
39
+ groups.push({ versions: v.slice(i, i + SIZE).join(' ') });
40
+ }
41
+ console.log('matrix='+JSON.stringify({'include': groups}))
37
42
  " >> $GITHUB_OUTPUT
38
43
 
39
44
  MinecraftServer:
40
45
  needs: PrepareSupportedVersions
41
46
  runs-on: ubuntu-latest
47
+ name: MC ${{ matrix.versions }}
42
48
  strategy:
43
- matrix: ${{fromJson(needs.PrepareSupportedVersions.outputs.matrix)}}
49
+ matrix: ${{ fromJson(needs.PrepareSupportedVersions.outputs.matrix) }}
44
50
  fail-fast: false
45
51
 
46
52
  steps:
@@ -58,4 +64,33 @@ jobs:
58
64
  run: npm install
59
65
 
60
66
  - name: Start Tests
61
- run: npm run mocha_test -- --retries 2 -g ${{ matrix.mcVersion }}v
67
+ run: |
68
+ exit_code=0
69
+ pids=""
70
+ for v in ${{ matrix.versions }}; do
71
+ npm run mocha_test -- --retries 3 -g "${v}v" > "test-${v}.log" 2>&1 &
72
+ pids="$pids $!"
73
+ done
74
+ for pid in $pids; do
75
+ wait $pid || exit_code=$?
76
+ done
77
+ # Print passing versions first, then failing versions last
78
+ for v in ${{ matrix.versions }}; do
79
+ if ! grep -q "failing" "test-${v}.log"; then
80
+ echo ""
81
+ echo "=========================================="
82
+ echo " Results for Minecraft ${v}"
83
+ echo "=========================================="
84
+ cat "test-${v}.log"
85
+ fi
86
+ done
87
+ for v in ${{ matrix.versions }}; do
88
+ if grep -q "failing" "test-${v}.log"; then
89
+ echo ""
90
+ echo "=========================================="
91
+ echo " FAILED: Minecraft ${v}"
92
+ echo "=========================================="
93
+ cat "test-${v}.log"
94
+ fi
95
+ done
96
+ exit $exit_code
package/docs/history.md CHANGED
@@ -1,4 +1,23 @@
1
- ## 4.35.0
1
+ ## 4.37.0
2
+
3
+ ## 4.37.1
4
+ * [Convert yaw/pitch in sync_entity_position handler (#3896)](https://github.com/PrismarineJS/mineflayer/commit/2b65c14c6d335758d1fe753ade99d736b610413b) (thanks @domdomegg)
5
+ * [Backport velocity field changes from 1.21.9+ to older versions (#3839)](https://github.com/PrismarineJS/mineflayer/commit/61fbd3a38177bde100b4ee9e130ccbcdb73fc7ea) (thanks @SuperGamerTron)
6
+ * [Update history.md](https://github.com/PrismarineJS/mineflayer/commit/fd00edd4a0211e8f131abf23b0951e04acceb3f5) (thanks @extremeheat)
7
+ * [Fix activateItem always having the same rotation (#3840)](https://github.com/PrismarineJS/mineflayer/commit/47a41c666f1f6e6783867ebe81e7386bbae72c24) (thanks @SuperGamerTron)
8
+ * [Fix crash in digging plugin death handler (#3553) (#3835)](https://github.com/PrismarineJS/mineflayer/commit/8af96fc0186ab770174744ea3e1f247c229a8cb3) (thanks @plainprince)
9
+ * [Fix crash issue when trying to parse bad skin JSON (#3712)](https://github.com/PrismarineJS/mineflayer/commit/dcbc5b2d605e38379724ca36467a911dc9cc562f) (thanks @TheSharkyOfficial)
10
+ * [Patches isInWater for digSpeed (#3542)](https://github.com/PrismarineJS/mineflayer/commit/a516d1cdf21ce2676195c595a64798c6ad29c195) (thanks @Pix3lPirat3)
11
+ * [fix firing heldItemChanged, add type (#3625)](https://github.com/PrismarineJS/mineflayer/commit/c5e0200686c269617f2a92c8db50fdceb899ba8a) (thanks @zardoy)
12
+ * [Fix dimension type lookup for 1.19-1.20.4 on proxy/modded servers (#3822)](https://github.com/PrismarineJS/mineflayer/commit/6d5d3ae576030bbe388f4d36dbc5d4eee99458bf) (thanks @plainprince)
13
+ * [Use minecraft-protocol ^1.66.0 with sync zlib fix (#3878)](https://github.com/PrismarineJS/mineflayer/commit/dc5c91a25a1f0d374017a2d1551b37396be7f658) (thanks @rom1504)
14
+
15
+ * [CI: print failed version logs last for easy debugging (#3876)](https://github.com/PrismarineJS/mineflayer/commit/56efbcde16343576533eaa7a08e85b785ae847cd) (thanks @rom1504)
16
+ * [Fix nether test reliability and add set_player_inventory handler (#3874)](https://github.com/PrismarineJS/mineflayer/commit/fd03f0a83e00229344b0624ce5ace9e0303599f3) (thanks @rom1504)
17
+ * [Improve test reliability: reconnect, retry, server console, packet fix (#3873)](https://github.com/PrismarineJS/mineflayer/commit/23f60d2132d49c08d936073d215466a825045933) (thanks @rom1504)
18
+ * [Improve test reliability: server console gamemode, retries, NaN guard (#3871)](https://github.com/PrismarineJS/mineflayer/commit/7af5e2ccf2f7ed1240ea792cb425a20e669618c2) (thanks @rom1504)
19
+ * [CI: run 4 MC versions per job to halve runner pressure (#3870)](https://github.com/PrismarineJS/mineflayer/commit/85a164d86e2b8bac996946ef6fb46d800861c82f) (thanks @rom1504)
20
+ * [Speed up tests: remove sleep(1000) in resetState (#3869)](https://github.com/PrismarineJS/mineflayer/commit/81ecd72bafafc711ee2bc32b19d64f2bd897c4fb) (thanks @rom1504)
2
21
 
3
22
  ## 4.36.0
4
23
  * [Update CI to Node 24 (#3861)](https://github.com/PrismarineJS/mineflayer/commit/3b05f83d536adb31103c811f7093361ff35449a1) (thanks @rom1504)
@@ -6,6 +25,7 @@
6
25
  * [Switch to trusted publishing via OIDC (#3856)](https://github.com/PrismarineJS/mineflayer/commit/3173eeded3982b144bc40d7b0fdfb083ee7eb118) (thanks @rom1504)
7
26
  * [Bump @types/node to 25.2.1 + fix flaky time & nether tests (#3828)](https://github.com/PrismarineJS/mineflayer/commit/89686596c8de1091bf45104ba3230a5e87707a20) (thanks @plainprince)
8
27
 
28
+ ## 4.35.0
9
29
  * [🎈 1.21.11 (#3781)](https://github.com/PrismarineJS/mineflayer/commit/597745c7c061943620fcacba7254bccee05b7a3e) (thanks @rom1504bot)
10
30
  * [Fix chat pattern and event listener in tutorial (#3783)](https://github.com/PrismarineJS/mineflayer/commit/48586138f560991de60bea639c71fa82954cf50f) (thanks @brentspine)
11
31
  * [Update history.md](https://github.com/PrismarineJS/mineflayer/commit/c9f766513d5bb5a93c5b86c07827128716c0afdb) (thanks @extremeheat)
package/index.d.ts CHANGED
@@ -162,6 +162,7 @@ export interface BotEvents {
162
162
  bossBarDeleted: (bossBar: BossBar) => Promise<void> | void
163
163
  bossBarUpdated: (bossBar: BossBar) => Promise<void> | void
164
164
  resourcePack: (url: string, hash?: string, uuid?: string) => Promise<void> | void
165
+ heldItemChanged: (newItem: Item | null) => Promise<void> | void
165
166
  particle: (particle: Particle) => Promise<void> | void
166
167
  }
167
168
 
@@ -386,8 +387,8 @@ export interface Bot extends TypedEmitter<BotEvents> {
386
387
  times?: number
387
388
  ) => Promise<void>
388
389
 
389
-
390
-
390
+
391
+
391
392
  setCommandBlock: (pos: Vec3, command: string, options: CommandBlockOptions) => void
392
393
 
393
394
  clickWindow: (
@@ -210,9 +210,11 @@ function inject (bot) {
210
210
  }
211
211
 
212
212
  bot.on('death', () => {
213
- bot.removeAllListeners('diggingAborted')
214
- bot.removeAllListeners('diggingCompleted')
215
- bot.stopDigging()
213
+ try {
214
+ bot.removeAllListeners('diggingAborted')
215
+ bot.removeAllListeners('diggingCompleted')
216
+ bot.stopDigging()
217
+ } catch (_) {}
216
218
  })
217
219
 
218
220
  function canDigBlock (block) {
@@ -246,13 +248,14 @@ function inject (bot) {
246
248
  return block.digTime(
247
249
  type,
248
250
  creative,
249
- bot.entity.isInWater,
251
+ ['water', 'flowing_water'].includes(bot._getBlockAtEyeLevel()?.name),
250
252
  !bot.entity.onGround,
251
253
  enchantments,
252
254
  bot.entity.effects
253
255
  )
254
256
  }
255
257
 
258
+ bot._getBlockAtEyeLevel = () => bot.entity.position && bot.blockAt(bot.entity.position.offset(0, bot.entity.eyeHeight, 0))
256
259
  bot.dig = dig
257
260
  bot.stopDigging = noop
258
261
  bot.canDigBlock = canDigBlock
@@ -1,5 +1,6 @@
1
1
  const { Vec3 } = require('vec3')
2
2
  const conv = require('../conversions')
3
+ const mojangson = require('mojangson')
3
4
  // These values are only accurate for versions 1.14 and above (crouch hitbox changes)
4
5
  // Todo: hitbox sizes for sleeping, swimming/crawling, and flying with elytra
5
6
  const PLAYER_HEIGHT = 1.8
@@ -270,13 +271,7 @@ function inject (bot) {
270
271
  entity.yaw = conv.fromNotchianYawByte(packet.yaw)
271
272
  entity.pitch = conv.fromNotchianPitchByte(packet.pitch)
272
273
  entity.headPitch = conv.fromNotchianPitchByte(packet.headPitch)
273
-
274
- let notchVel
275
- if (bot.supportFeature('entityVelocityIsLpVec3')) {
276
- notchVel = new Vec3(packet.velocity.x, packet.velocity.y, packet.velocity.z)
277
- } else {
278
- notchVel = new Vec3(packet.velocityX, packet.velocityY, packet.velocityZ)
279
- }
274
+ const notchVel = new Vec3(packet.velocity.x, packet.velocity.y, packet.velocity.z)
280
275
  entity.velocity.update(conv.fromNotchVelocity(notchVel))
281
276
  entity.metadata = parseMetadata(packet.metadata, entity.metadata)
282
277
 
@@ -286,12 +281,7 @@ function inject (bot) {
286
281
  bot._client.on('entity_velocity', (packet) => {
287
282
  // entity velocity
288
283
  const entity = fetchEntity(packet.entityId)
289
- let notchVel
290
- if (bot.supportFeature('entityVelocityIsLpVec3')) {
291
- notchVel = new Vec3(packet.velocity.x, packet.velocity.y, packet.velocity.z)
292
- } else {
293
- notchVel = new Vec3(packet.velocityX, packet.velocityY, packet.velocityZ)
294
- }
284
+ const notchVel = new Vec3(packet.velocity.x, packet.velocity.y, packet.velocity.z)
295
285
  entity.velocity.update(conv.fromNotchVelocity(notchVel))
296
286
  })
297
287
 
@@ -359,8 +349,8 @@ function inject (bot) {
359
349
  const entity = fetchEntity(packet.entityId)
360
350
  entity.position.set(packet.x, packet.y, packet.z)
361
351
  entity.velocity.set(packet.dx, packet.dy, packet.dz)
362
- entity.yaw = packet.yaw
363
- entity.pitch = packet.pitch
352
+ entity.yaw = conv.fromNotchianYaw(packet.yaw)
353
+ entity.pitch = conv.fromNotchianPitch(packet.pitch)
364
354
  bot.emit('entityMoved', entity)
365
355
  })
366
356
 
@@ -953,7 +943,12 @@ function extractSkinInformation (properties) {
953
943
  return undefined
954
944
  }
955
945
 
956
- const skinTexture = JSON.parse(Buffer.from(props.textures.value, 'base64').toString('utf8'))
946
+ let skinTexture
947
+ try { // Handles mojangson-style player data
948
+ skinTexture = JSON.parse(Buffer.from(props.textures.value, 'base64'))
949
+ } catch (e) {
950
+ skinTexture = mojangson.simplify(mojangson.parse(Buffer.from(props.textures.value, 'base64').toString('utf-8')))
951
+ }
957
952
 
958
953
  const skinTextureUrl = skinTexture?.textures?.SKIN?.url ?? undefined
959
954
  const skinTextureModel = skinTexture?.textures?.SKIN?.metadata?.model ?? undefined
@@ -47,7 +47,18 @@ function inject (bot, options) {
47
47
  } else if (bot.supportFeature('dimensionIsAString')) {
48
48
  bot.game.dimension = packet.dimension.replace('minecraft:', '')
49
49
  } else if (bot.supportFeature('dimensionIsAWorld')) {
50
- bot.game.dimension = packet.worldName.replace('minecraft:', '')
50
+ if (bot.supportFeature('dimensionDataInCodec')) {
51
+ // For 1.19+, we need the dimension TYPE name (not the world/level name) so
52
+ // the codec lookup succeeds. In login packets the type is "worldType"; in
53
+ // respawn packets it is "dimension". worldName is the level name which may
54
+ // differ from the type on proxy/modded servers.
55
+ const dimType = packet.worldType ?? packet.dimension
56
+ bot.game.dimension = typeof dimType === 'string'
57
+ ? dimType.replace('minecraft:', '')
58
+ : packet.worldName.replace('minecraft:', '')
59
+ } else {
60
+ bot.game.dimension = packet.worldName.replace('minecraft:', '')
61
+ }
51
62
  } else {
52
63
  throw new Error('Unsupported dimension type in login packet')
53
64
  }
@@ -60,11 +71,6 @@ function inject (bot, options) {
60
71
  bot.game.height = 256
61
72
 
62
73
  if (bot.supportFeature('dimensionDataInCodec')) { // 1.19+
63
- // pre 1.20.5 before we consolidated login and respawn's SpawnInfo structure into one type,
64
- // "dimension" was called "worldType" in login_packet's payload but not respawn.
65
- if (packet.worldType && !bot.game.dimension) {
66
- bot.game.dimension = packet.worldType.replace('minecraft:', '')
67
- }
68
74
  const dimData = bot.registry.dimensionsByName[bot.game.dimension]
69
75
  if (dimData) {
70
76
  bot.game.minY = dimData.minY
@@ -1,6 +1,7 @@
1
1
  const assert = require('assert')
2
2
  const { Vec3 } = require('vec3')
3
3
  const { once, sleep, createDoneTask, createTask, withTimeout } = require('../promise_utils')
4
+ const { toNotchianYaw, toNotchianPitch } = require('../conversions')
4
5
 
5
6
  module.exports = inject
6
7
 
@@ -128,7 +129,10 @@ function inject (bot, { hideErrors }) {
128
129
  bot._client.write('use_item', {
129
130
  hand: offHand ? 1 : 0,
130
131
  sequence,
131
- rotation: { x: 0, y: 0 }
132
+ rotation: {
133
+ x: toNotchianYaw(bot.entity.yaw),
134
+ y: toNotchianPitch(bot.entity.pitch)
135
+ }
132
136
  })
133
137
  }
134
138
  }
@@ -547,7 +551,7 @@ function inject (bot, { hideErrors }) {
547
551
  }
548
552
  const window = bot.currentWindow || bot.inventory
549
553
 
550
- assert.ok(mode >= 0 && mode <= 4)
554
+ assert.ok(mode >= 0 && mode <= 6)
551
555
  const actionId = createActionNumber()
552
556
 
553
557
  const click = {
@@ -728,6 +732,17 @@ function inject (bot, { hideErrors }) {
728
732
  const newItem = Item.fromNotch(packet.item)
729
733
  bot._setSlot(packet.slot, newItem, window)
730
734
  })
735
+ // 1.21.9+ uses set_player_inventory for server-initiated inventory changes
736
+ // (e.g. console /give) instead of set_slot
737
+ bot._client.on('set_player_inventory', (packet) => {
738
+ const newItem = Item.fromNotch(packet.contents)
739
+ bot._setSlot(packet.slotId, newItem)
740
+ })
741
+ bot.inventory.on('updateSlot', (index) => {
742
+ if (index === bot.quickBarSlot + bot.inventory.hotbarStart) {
743
+ bot.emit('heldItemChanged', bot.heldItem)
744
+ }
745
+ })
731
746
  bot._client.on('window_items', (packet) => {
732
747
  const window = packet.windowId === 0 ? bot.inventory : bot.currentWindow
733
748
  if (!window || window.id !== packet.windowId) {
@@ -76,6 +76,7 @@ function inject (bot, { physicsEnabled, maxCatchupTicks }) {
76
76
  }
77
77
 
78
78
  function tickPhysics (now) {
79
+ if (!bot.entity?.position || !Number.isFinite(bot.entity.position.x)) return // entity not ready
79
80
  if (bot.blockAt(bot.entity.position) == null) return // check if chunk is unloaded
80
81
  if (bot.physicsEnabled && shouldUsePhysics) {
81
82
  physics.simulatePlayer(new PlayerState(bot, controlState), world).apply(bot)
@@ -99,6 +100,7 @@ function inject (bot, { physicsEnabled, maxCatchupTicks }) {
99
100
 
100
101
  function sendPacketPosition (position, onGround) {
101
102
  // sends data, no logic
103
+ if (!Number.isFinite(position.x) || !Number.isFinite(position.y) || !Number.isFinite(position.z)) return
102
104
  const oldPos = new Vec3(lastSent.x, lastSent.y, lastSent.z)
103
105
  lastSent.x = position.x
104
106
  lastSent.y = position.y
@@ -122,6 +124,7 @@ function inject (bot, { physicsEnabled, maxCatchupTicks }) {
122
124
 
123
125
  function sendPacketPositionAndLook (position, yaw, pitch, onGround) {
124
126
  // sends data, no logic
127
+ if (!Number.isFinite(position.x) || !Number.isFinite(position.y) || !Number.isFinite(position.z)) return
125
128
  const oldPos = new Vec3(lastSent.x, lastSent.y, lastSent.z)
126
129
  lastSent.x = position.x
127
130
  lastSent.y = position.y
@@ -153,6 +156,8 @@ function inject (bot, { physicsEnabled, maxCatchupTicks }) {
153
156
  function updatePosition (now) {
154
157
  // Only send updates for 20 ticks after death
155
158
  if (isEntityRemoved()) return
159
+ // Don't send position with invalid coordinates (NaN after death)
160
+ if (!Number.isFinite(bot.entity.position.x)) return
156
161
 
157
162
  // Increment the yaw in baby steps so that notchian clients (not the server) can keep up.
158
163
  const dYaw = deltaYaw(bot.entity.yaw, lastSentYaw)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mineflayer",
3
- "version": "4.36.0",
3
+ "version": "4.37.1",
4
4
  "description": "create minecraft bots with a stable, high level API",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -22,7 +22,8 @@
22
22
  "license": "MIT",
23
23
  "dependencies": {
24
24
  "minecraft-data": "^3.108.0",
25
- "minecraft-protocol": "^1.64.0",
25
+ "minecraft-protocol": "^1.66.0",
26
+ "mojangson": "^2.0.4",
26
27
  "prismarine-biome": "^1.1.1",
27
28
  "prismarine-block": "^1.22.0",
28
29
  "prismarine-chat": "^1.7.1",