mineflayer 4.11.0 → 4.13.0

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.
@@ -12,10 +12,10 @@ jobs:
12
12
 
13
13
  steps:
14
14
  - uses: actions/checkout@v2
15
- - name: Use Node.js 14.x
15
+ - name: Use Node.js 18.x
16
16
  uses: actions/setup-node@v1.4.4
17
17
  with:
18
- node-version: 14.x
18
+ node-version: 18.x
19
19
  - run: npm i && npm run lint
20
20
 
21
21
  MinecraftServer:
@@ -46,7 +46,7 @@ jobs:
46
46
  - name: Use Node.js ${{ matrix.node-version }}
47
47
  uses: actions/setup-node@v1.4.4
48
48
  with:
49
- node-version: 14.x
49
+ node-version: 18.x
50
50
  - name: Setup Java JDK
51
51
  uses: actions/setup-java@v1.4.3
52
52
  with:
@@ -13,7 +13,7 @@ jobs:
13
13
  - name: Set up Node.js
14
14
  uses: actions/setup-node@master
15
15
  with:
16
- node-version: 14.0.0
16
+ node-version: 18.0.0
17
17
  - id: publish
18
18
  uses: JS-DevTools/npm-publish@v1
19
19
  with:
package/.gitpod.yml CHANGED
@@ -1,4 +1,2 @@
1
- image:
2
- file: .gitpod.DockerFile
3
1
  tasks:
4
2
  - command: npm install
package/README.md CHANGED
@@ -80,11 +80,11 @@ const mineflayer = require('mineflayer')
80
80
 
81
81
  const bot = mineflayer.createBot({
82
82
  host: 'localhost', // minecraft server ip
83
- username: 'email@example.com', // minecraft username
83
+ username: 'Bot', // username or email, switch if you want to change accounts
84
84
  auth: 'microsoft' // for offline mode servers, you can set this to 'offline'
85
85
  // port: 25565, // only set if you need a port that isn't 25565
86
86
  // version: false, // only set if you need a specific version or snapshot (ie: "1.8.9" or "1.16.5"), otherwise it's set automatically
87
- // password: '12345678' // set if you want to use password-based auth (may be unreliable)
87
+ // password: '12345678' // set if you want to use password-based auth (may be unreliable). If specified, the `username` must be an email
88
88
  })
89
89
 
90
90
  bot.on('chat', (username, message) => {
@@ -97,6 +97,26 @@ bot.on('kicked', console.log)
97
97
  bot.on('error', console.log)
98
98
  ```
99
99
 
100
+ If `auth` is set to `microsoft`, you will be prompted to login to microsoft.com with a code in your browser. After signing in on your browser,
101
+ the bot will automatically obtain and cache authentication tokens in the local file system so you don't have to sign-in again.
102
+ To switch the account, update the supplied `username`. By default, cached tokens will be stored in your user's .minecraft folder.
103
+ For more information on these options and others, see node-minecraft-protocol's [API doc](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/docs/API.md#mccreateclientoptions).
104
+
105
+ #### Connecting to a Realm
106
+
107
+ To join a Realm that your Minecraft account has been invited to, you can pass a `realms` object with a selector function like below.
108
+
109
+ ```js
110
+ const client = mineflayer.createBot({
111
+ username: 'email@example.com', // minecraft username
112
+ realms: {
113
+ // This function is called with an array of Realms the account can join. It should return the one it wants to join.
114
+ pickRealm: (realms) => realms[0]
115
+ },
116
+ auth: 'microsoft'
117
+ })
118
+ ```
119
+
100
120
  ### See what your bot is doing
101
121
 
102
122
  Thanks to the [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) project, it's possible to display in a browser window what your bot is doing.
@@ -220,6 +240,7 @@ The most updated and useful are :
220
240
  * [Chaoscraft](https://github.com/schematical/chaoscraft) - Minecraft bot using genetic algorithms, see [its youtube videos](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)
221
241
  * [hexatester/minetelegram](https://github.com/hexatester/minetelegram) - Minecraft - Telegram bridge, build on top of mineflayer & telegraf.
222
242
  * [PrismarineJS/mineflayer-builder](https://github.com/PrismarineJS/mineflayer-builder) - Prints minecraft schematics in survival, keeping orientation
243
+ * [SilkePilon/OpenDeliveryBot](https://github.com/SilkePilon/OpenDeliveryBot) - Minecraft bot in python to deliver items from place to place.
223
244
  * [and hundreds more](https://github.com/PrismarineJS/mineflayer/network/dependents) - All the projects that github detected are using mineflayer
224
245
 
225
246
 
package/docs/README.md CHANGED
@@ -80,11 +80,11 @@ const mineflayer = require('mineflayer')
80
80
 
81
81
  const bot = mineflayer.createBot({
82
82
  host: 'localhost', // minecraft server ip
83
- username: 'email@example.com', // minecraft username
83
+ username: 'Bot', // username or email, switch if you want to change accounts
84
84
  auth: 'microsoft' // for offline mode servers, you can set this to 'offline'
85
85
  // port: 25565, // only set if you need a port that isn't 25565
86
86
  // version: false, // only set if you need a specific version or snapshot (ie: "1.8.9" or "1.16.5"), otherwise it's set automatically
87
- // password: '12345678' // set if you want to use password-based auth (may be unreliable)
87
+ // password: '12345678' // set if you want to use password-based auth (may be unreliable). If specified, the `username` must be an email
88
88
  })
89
89
 
90
90
  bot.on('chat', (username, message) => {
@@ -97,6 +97,26 @@ bot.on('kicked', console.log)
97
97
  bot.on('error', console.log)
98
98
  ```
99
99
 
100
+ If `auth` is set to `microsoft`, you will be prompted to login to microsoft.com with a code in your browser. After signing in on your browser,
101
+ the bot will automatically obtain and cache authentication tokens in the local file system so you don't have to sign-in again.
102
+ To switch the account, update the supplied `username`. By default, cached tokens will be stored in your user's .minecraft folder.
103
+ For more information on these options and others, see node-minecraft-protocol's [API doc](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/docs/API.md#mccreateclientoptions).
104
+
105
+ #### Connecting to a Realm
106
+
107
+ To join a Realm that your Minecraft account has been invited to, you can pass a `realms` object with a selector function like below.
108
+
109
+ ```js
110
+ const client = mineflayer.createBot({
111
+ username: 'email@example.com', // minecraft username
112
+ realms: {
113
+ // This function is called with an array of Realms the account can join. It should return the one it wants to join.
114
+ pickRealm: (realms) => realms[0]
115
+ },
116
+ auth: 'microsoft'
117
+ })
118
+ ```
119
+
100
120
  ### See what your bot is doing
101
121
 
102
122
  Thanks to the [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) project, it's possible to display in a browser window what your bot is doing.
@@ -220,6 +240,7 @@ The most updated and useful are :
220
240
  * [Chaoscraft](https://github.com/schematical/chaoscraft) - Minecraft bot using genetic algorithms, see [its youtube videos](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)
221
241
  * [hexatester/minetelegram](https://github.com/hexatester/minetelegram) - Minecraft - Telegram bridge, build on top of mineflayer & telegraf.
222
242
  * [PrismarineJS/mineflayer-builder](https://github.com/PrismarineJS/mineflayer-builder) - Prints minecraft schematics in survival, keeping orientation
243
+ * [SilkePilon/OpenDeliveryBot](https://github.com/SilkePilon/OpenDeliveryBot) - Minecraft bot in python to deliver items from place to place.
223
244
  * [and hundreds more](https://github.com/PrismarineJS/mineflayer/network/dependents) - All the projects that github detected are using mineflayer
224
245
 
225
246
 
package/docs/history.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 4.13.0
2
+ * [Switch to entity.displayName (#3168)](https://github.com/PrismarineJS/mineflayer/commit/2409ad458b952173de669a7d9cfaeb770effe3ae) (thanks @lkwilson)
3
+ * [Update readme auth doc (#3169)](https://github.com/PrismarineJS/mineflayer/commit/f5d4a288a768ca6717fa4d22c72fb0267428c684) (thanks @extremeheat)
4
+ * [Add OpenDeliveryBot to "Projects Using Mineflayer" (#3162)](https://github.com/PrismarineJS/mineflayer/commit/ab3c0cf25d0cc28ccba89640b2ceff6ab6b4dace) (thanks @SilkePilon)
5
+ * [Use node 18 on CI (#3157)](https://github.com/PrismarineJS/mineflayer/commit/d3df34dcaa804a71bf0d8cc50a419990d4a2dce3) (thanks @extremeheat)
6
+ * [Fix ambigious function naming (#3161)](https://github.com/PrismarineJS/mineflayer/commit/9ecdf201794bfa350486839a01e318dfd94b3bfb) (thanks @frej4189)
7
+
8
+ ## 4.12.0
9
+ * [Mineflayer physics refactor (#2492)](https://github.com/PrismarineJS/mineflayer/commit/d0eb3a1afe6cda7b04ae2f88052cd868ba0c0c4f) (thanks @U5B)
10
+
1
11
  ## 4.11.0
2
12
  * [Import changedSlots computation from prismarine-windows (#3134)](https://github.com/PrismarineJS/mineflayer/commit/e5b5eeecf1133c1c80c0ef48d6e72fed77d84834) (thanks @kaduvert)
3
13
  * [Make the place block success check ignore block updates received with no block type changes (#3090)](https://github.com/PrismarineJS/mineflayer/commit/bbdd93afe2e31d1f1e899176e7edf8e73af5d5d3) (thanks @PondWader)
@@ -26,7 +26,7 @@ bot.on('chat', async (username, message) => {
26
26
  const [mainCommand, subCommand] = message.split(' ')
27
27
  if (mainCommand !== 'equip' && mainCommand !== 'unequip') return
28
28
 
29
- const armorStand = bot.nearestEntity(e => e.mobType === 'Armor Stand' && bot.entity.position.distanceTo(e.position) < 4)
29
+ const armorStand = bot.nearestEntity(e => e.displayName === 'Armor Stand' && bot.entity.position.distanceTo(e.position) < 4)
30
30
  if (!armorStand) {
31
31
  bot.chat('No armor stands nearby!')
32
32
  return
@@ -176,11 +176,11 @@ bot.on('playerCollect', (collector, collected) => {
176
176
 
177
177
  bot.on('entitySpawn', (entity) => {
178
178
  if (entity.type === 'mob') {
179
- console.log(`Look out! A ${entity.mobType} spawned at ${entity.position}`)
179
+ console.log(`Look out! A ${entity.displayName} spawned at ${entity.position}`)
180
180
  } else if (entity.type === 'player') {
181
181
  bot.chat(`Look who decided to show up: ${entity.username}`)
182
182
  } else if (entity.type === 'object') {
183
- console.log(`There's a ${entity.objectType} at ${entity.position}`)
183
+ console.log(`There's a ${entity.displayName} at ${entity.position}`)
184
184
  } else if (entity.type === 'global') {
185
185
  bot.chat('Ooh lightning!')
186
186
  } else if (entity.type === 'orb') {
@@ -189,7 +189,7 @@ bot.on('entitySpawn', (entity) => {
189
189
  })
190
190
  bot.on('entityHurt', (entity) => {
191
191
  if (entity.type === 'mob') {
192
- bot.chat(`Haha! The ${entity.mobType} got hurt!`)
192
+ bot.chat(`Haha! The ${entity.displayName} got hurt!`)
193
193
  } else if (entity.type === 'player') {
194
194
  bot.chat(`Aww, poor ${entity.username} got hurt. Maybe you shouldn't have a ping of ${bot.players[entity.username].ping}`)
195
195
  }
@@ -214,12 +214,12 @@ bot.on('entityEat', (entity) => {
214
214
  })
215
215
  bot.on('entityAttach', (entity, vehicle) => {
216
216
  if (entity.type === 'player' && vehicle.type === 'object') {
217
- bot.chat(`Sweet, ${entity.username} is riding that ${vehicle.objectType}`)
217
+ bot.chat(`Sweet, ${entity.username} is riding that ${vehicle.displayName}`)
218
218
  }
219
219
  })
220
220
  bot.on('entityDetach', (entity, vehicle) => {
221
221
  if (entity.type === 'player' && vehicle.type === 'object') {
222
- bot.chat(`Lame, ${entity.username} stopped riding the ${vehicle.objectType}`)
222
+ bot.chat(`Lame, ${entity.username} stopped riding the ${vehicle.displayName}`)
223
223
  }
224
224
  })
225
225
  bot.on('entityEquipmentChange', (entity) => {
package/examples/guard.js CHANGED
@@ -59,7 +59,7 @@ bot.on('physicsTick', () => {
59
59
 
60
60
  // Only look for mobs within 16 blocks
61
61
  const filter = e => e.type === 'mob' && e.position.distanceTo(bot.entity.position) < 16 &&
62
- e.mobType !== 'Armor Stand' // Mojang classifies armor stands as mobs for some reason?
62
+ e.displayName !== 'Armor Stand' // Mojang classifies armor stands as mobs for some reason?
63
63
 
64
64
  const entity = bot.nearestEntity(filter)
65
65
  if (entity) {
@@ -108,9 +108,9 @@ bot.once('spawn', () => {
108
108
  })
109
109
 
110
110
  bot.on('mount', () => {
111
- bot.chat(`mounted ${bot.vehicle.objectType}`)
111
+ bot.chat(`mounted ${bot.vehicle.displayName}`)
112
112
  })
113
113
 
114
114
  bot.on('dismount', (vehicle) => {
115
- bot.chat(`dismounted ${vehicle.objectType}`)
115
+ bot.chat(`dismounted ${vehicle.displayName}`)
116
116
  })
@@ -224,12 +224,12 @@ def playerCollect(this, collector, collected):
224
224
  def entitySpawn(this, entity):
225
225
  if entity.type == "mob":
226
226
  p = entity.position
227
- console.log(f"Look out! A {entity.mobType} spawned at {p.toString()}")
227
+ console.log(f"Look out! A {entity.displayName} spawned at {p.toString()}")
228
228
  elif entity.type == "player":
229
229
  bot.chat(f"Look who decided to show up: {entity.username}")
230
230
  elif entity.type == "object":
231
231
  p = entity.position
232
- console.log(f"There's a {entity.objectType} at {p.toString()}")
232
+ console.log(f"There's a {entity.displayName} at {p.toString()}")
233
233
  elif entity.type == "global":
234
234
  bot.chat("Ooh lightning!")
235
235
  elif entity.type == "orb":
@@ -239,7 +239,7 @@ def entitySpawn(this, entity):
239
239
  @On(bot, "entityHurt")
240
240
  def entityHurt(this, entity):
241
241
  if entity.type == "mob":
242
- bot.chat(f"Haha! The ${entity.mobType} got hurt!")
242
+ bot.chat(f"Haha! The ${entity.displayName} got hurt!")
243
243
  elif entity.type == "player":
244
244
  if entity.username in bot.players:
245
245
  ping = bot.players[entity.username].ping
@@ -279,13 +279,13 @@ def entityEat(this, entity):
279
279
  @On(bot, "entityAttach")
280
280
  def entityAttach(this, entity, vehicle):
281
281
  if entity.type == "player" and vehicle.type == "object":
282
- print(f"Sweet, {entity.username} is riding that {vehicle.objectType}")
282
+ print(f"Sweet, {entity.username} is riding that {vehicle.displayName}")
283
283
 
284
284
 
285
285
  @On(bot, "entityDetach")
286
286
  def entityDetach(this, entity, vehicle):
287
287
  if entity.type == "player" and vehicle.type == "object":
288
- print(f"Lame, {entity.username} stopped riding the {vehicle.objectType}")
288
+ print(f"Lame, {entity.username} stopped riding the {vehicle.displayName}")
289
289
 
290
290
 
291
291
  @On(bot, "entityEquipmentChange")
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
- if (typeof process !== 'undefined' && parseInt(process.versions.node.split('.')[0]) < 14) {
1
+ if (typeof process !== 'undefined' && parseInt(process.versions.node.split('.')[0]) < 18) {
2
2
  console.error('Your node version is currently', process.versions.node)
3
- console.error('Please update it to a version >= 14.x.x from https://nodejs.org/')
3
+ console.error('Please update it to a version >= 18.x.x from https://nodejs.org/')
4
4
  process.exit(1)
5
5
  }
6
6
 
@@ -176,8 +176,6 @@ function inject (bot) {
176
176
  entityData = entitiesArray.find(entity => entity.internalId === type)
177
177
  }
178
178
  if (entityData) {
179
- entity.mobType = entityData.displayName
180
- entity.objectType = entityData.displayName
181
179
  entity.displayName = entityData.displayName
182
180
  entity.entityType = entityData.id
183
181
  entity.name = entityData.name
@@ -188,7 +186,6 @@ function inject (bot) {
188
186
  // unknown entity
189
187
  entity.type = 'other'
190
188
  entity.entityType = type
191
- entity.mobType = 'unknown'
192
189
  entity.displayName = 'unknown'
193
190
  entity.name = 'unknown'
194
191
  entity.kind = 'unknown'
@@ -12,9 +12,10 @@ module.exports = inject
12
12
  const PI = Math.PI
13
13
  const PI_2 = Math.PI * 2
14
14
  const PHYSICS_INTERVAL_MS = 50
15
- const PHYSICS_TIMESTEP = PHYSICS_INTERVAL_MS / 1000
15
+ const PHYSICS_TIMESTEP = PHYSICS_INTERVAL_MS / 1000 // 0.05
16
16
 
17
- function inject (bot, { physicsEnabled }) {
17
+ function inject (bot, { physicsEnabled, maxCatchupTicks }) {
18
+ const PHYSICS_CATCHUP_TICKS = maxCatchupTicks ?? 4
18
19
  const world = { getBlock: (pos) => { return bot.blockAt(pos, false) } }
19
20
  const physics = Physics(bot.registry, world)
20
21
 
@@ -38,6 +39,7 @@ function inject (bot, { physicsEnabled }) {
38
39
  let lastPhysicsFrameTime = null
39
40
  let shouldUsePhysics = false
40
41
  bot.physicsEnabled = physicsEnabled ?? true
42
+ let deadTicks = 21
41
43
 
42
44
  const lastSent = {
43
45
  x: 0,
@@ -51,25 +53,44 @@ function inject (bot, { physicsEnabled }) {
51
53
 
52
54
  // This function should be executed each tick (every 0.05 seconds)
53
55
  // How it works: https://gafferongames.com/post/fix_your_timestep/
56
+
57
+ // WARNING: THIS IS NOT ACCURATE ON WINDOWS (15.6 Timer Resolution)
58
+ // use WSL or switch to Linux
59
+ // see: https://discord.com/channels/413438066984747026/519952494768685086/901948718255833158
54
60
  let timeAccumulator = 0
61
+ let catchupTicks = 0
55
62
  function doPhysics () {
56
63
  const now = performance.now()
57
64
  const deltaSeconds = (now - lastPhysicsFrameTime) / 1000
58
65
  lastPhysicsFrameTime = now
59
66
 
60
67
  timeAccumulator += deltaSeconds
61
-
68
+ catchupTicks = 0
62
69
  while (timeAccumulator >= PHYSICS_TIMESTEP) {
63
- if (bot.physicsEnabled && shouldUsePhysics) {
64
- physics.simulatePlayer(new PlayerState(bot, controlState), world).apply(bot)
65
- bot.emit('physicsTick')
66
- bot.emit('physicTick') // Deprecated, only exists to support old plugins. May be removed in the future
67
- }
68
- updatePosition(PHYSICS_TIMESTEP)
70
+ tickPhysics(now)
69
71
  timeAccumulator -= PHYSICS_TIMESTEP
72
+ catchupTicks++
73
+ if (catchupTicks >= PHYSICS_CATCHUP_TICKS) break
74
+ }
75
+ }
76
+
77
+ function tickPhysics (now) {
78
+ if (bot.blockAt(bot.entity.position) == null) return // check if chunk is unloaded
79
+ if (bot.physicsEnabled && shouldUsePhysics) {
80
+ physics.simulatePlayer(new PlayerState(bot, controlState), world).apply(bot)
81
+ bot.emit('physicsTick')
82
+ bot.emit('physicTick') // Deprecated, only exists to support old plugins. May be removed in the future
83
+ }
84
+ if (shouldUsePhysics) {
85
+ updatePosition(now)
70
86
  }
71
87
  }
72
88
 
89
+ // remove this when 'physicTick' is removed
90
+ bot.on('newListener', (name) => {
91
+ if (name === 'physicTick') console.warn('Mineflayer detected that you are using a deprecated event (physicTick)! Please use this event (physicsTick) instead.')
92
+ })
93
+
73
94
  function cleanup () {
74
95
  clearInterval(doPhysicsTimer)
75
96
  doPhysicsTimer = null
@@ -117,17 +138,25 @@ function inject (bot, { physicsEnabled }) {
117
138
  return dYaw
118
139
  }
119
140
 
120
- function updatePosition (dt) {
121
- // If you're dead, you're probably on the ground though ...
122
- if (!bot.isAlive) bot.entity.onGround = true
141
+ // returns false if bot should send position packets
142
+ function isEntityRemoved () {
143
+ if (bot.isAlive === true) deadTicks = 0
144
+ if (bot.isAlive === false && deadTicks <= 20) deadTicks++
145
+ if (deadTicks >= 20) return true
146
+ return false
147
+ }
148
+
149
+ function updatePosition (now) {
150
+ // Only send updates for 20 ticks after death
151
+ if (isEntityRemoved()) return
123
152
 
124
153
  // Increment the yaw in baby steps so that notchian clients (not the server) can keep up.
125
154
  const dYaw = deltaYaw(bot.entity.yaw, lastSentYaw)
126
155
  const dPitch = bot.entity.pitch - (lastSentPitch || 0)
127
156
 
128
157
  // Vanilla doesn't clamp yaw, so we don't want to do it either
129
- const maxDeltaYaw = dt * physics.yawSpeed
130
- const maxDeltaPitch = dt * physics.pitchSpeed
158
+ const maxDeltaYaw = PHYSICS_TIMESTEP * physics.yawSpeed
159
+ const maxDeltaPitch = PHYSICS_TIMESTEP * physics.pitchSpeed
131
160
  lastSentYaw += math.clamp(-maxDeltaYaw, dYaw, maxDeltaYaw)
132
161
  lastSentPitch += math.clamp(-maxDeltaPitch, dPitch, maxDeltaPitch)
133
162
 
@@ -137,24 +166,28 @@ function inject (bot, { physicsEnabled }) {
137
166
  const onGround = bot.entity.onGround
138
167
 
139
168
  // Only send a position update if necessary, select the appropriate packet
140
- const positionUpdated = lastSent.x !== position.x || lastSent.y !== position.y || lastSent.z !== position.z
169
+ const positionUpdated = lastSent.x !== position.x || lastSent.y !== position.y || lastSent.z !== position.z ||
170
+ // Send a position update every second, even if no other update was made
171
+ // This function rounds to the nearest 50ms (or PHYSICS_INTERVAL_MS) and checks if a second has passed.
172
+ (Math.round((now - lastSent.time) / PHYSICS_INTERVAL_MS) * PHYSICS_INTERVAL_MS) >= 1000
141
173
  const lookUpdated = lastSent.yaw !== yaw || lastSent.pitch !== pitch
142
174
 
143
- if (positionUpdated && lookUpdated && bot.isAlive) {
175
+ if (positionUpdated && lookUpdated) {
144
176
  sendPacketPositionAndLook(position, yaw, pitch, onGround)
145
- } else if (positionUpdated && bot.isAlive) {
177
+ lastSent.time = now // only reset if positionUpdated is true
178
+ } else if (positionUpdated) {
146
179
  sendPacketPosition(position, onGround)
147
- } else if (lookUpdated && bot.isAlive) {
180
+ lastSent.time = now // only reset if positionUpdated is true
181
+ } else if (lookUpdated) {
148
182
  sendPacketLook(yaw, pitch, onGround)
149
- } else if (performance.now() - lastSent.time >= 1000) {
150
- // Send a position packet every second, even if no update was made
151
- sendPacketPosition(position, onGround)
152
- lastSent.time = performance.now()
153
- } else if (positionUpdateSentEveryTick && bot.isAlive) {
183
+ } else if (positionUpdateSentEveryTick || onGround !== lastSent.onGround) {
154
184
  // For versions < 1.12, one player packet should be sent every tick
155
185
  // for the server to update health correctly
186
+ // For versions >= 1.12, onGround !== lastSent.onGround should be used, but it doesn't ever trigger outside of login
156
187
  bot._client.write('flying', { onGround: bot.entity.onGround })
157
188
  }
189
+
190
+ lastSent.onGround = bot.entity.onGround // onGround is always set
158
191
  }
159
192
 
160
193
  bot.physics = physics
@@ -262,7 +295,14 @@ function inject (bot, { physicsEnabled }) {
262
295
  // player position and look (clientbound)
263
296
  bot._client.on('position', (packet) => {
264
297
  bot.entity.height = 1.62
265
- bot.entity.velocity.set(0, 0, 0)
298
+
299
+ // Velocity is only set to 0 if the flag is not set, otherwise keep current velocity
300
+ const vel = bot.entity.velocity
301
+ vel.set(
302
+ packet.flags & 1 ? vel.x : 0,
303
+ packet.flags & 2 ? vel.y : 0,
304
+ packet.flags & 4 ? vel.z : 0
305
+ )
266
306
 
267
307
  // If flag is set, then the corresponding value is relative, else it is absolute
268
308
  const pos = bot.entity.position
@@ -280,19 +320,14 @@ function inject (bot, { physicsEnabled }) {
280
320
 
281
321
  if (bot.supportFeature('teleportUsesOwnPacket')) {
282
322
  bot._client.write('teleport_confirm', { teleportId: packet.teleportId })
283
- // Force send an extra packet to be like vanilla client
284
- sendPacketPositionAndLook(pos, newYaw, newPitch, bot.entity.onGround)
285
323
  }
286
324
  sendPacketPositionAndLook(pos, newYaw, newPitch, bot.entity.onGround)
287
325
 
288
326
  shouldUsePhysics = true
289
- bot.entity.timeSinceOnGround = 0
327
+ bot.jumpTicks = 0
290
328
  lastSentYaw = bot.entity.yaw
329
+ lastSentPitch = bot.entity.pitch
291
330
 
292
- if (doPhysicsTimer === null) {
293
- lastPhysicsFrameTime = performance.now()
294
- doPhysicsTimer = setInterval(doPhysics, PHYSICS_INTERVAL_MS)
295
- }
296
331
  bot.emit('forcedMove')
297
332
  })
298
333
 
@@ -313,5 +348,12 @@ function inject (bot, { physicsEnabled }) {
313
348
 
314
349
  bot.on('mount', () => { shouldUsePhysics = false })
315
350
  bot.on('respawn', () => { shouldUsePhysics = false })
351
+ bot.on('login', () => {
352
+ shouldUsePhysics = false
353
+ if (doPhysicsTimer === null) {
354
+ lastPhysicsFrameTime = performance.now()
355
+ doPhysicsTimer = setInterval(doPhysics, PHYSICS_INTERVAL_MS)
356
+ }
357
+ })
316
358
  bot.on('end', cleanup)
317
359
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mineflayer",
3
- "version": "4.11.0",
3
+ "version": "4.13.0",
4
4
  "description": "create minecraft bots with a stable, high level API",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,7 +27,7 @@
27
27
  "prismarine-block": "^1.17.0",
28
28
  "prismarine-chat": "^1.7.1",
29
29
  "prismarine-chunk": "^1.34.0",
30
- "prismarine-entity": "^2.2.0",
30
+ "prismarine-entity": "^2.3.0",
31
31
  "prismarine-item": "^1.14.0",
32
32
  "prismarine-nbt": "^2.0.0",
33
33
  "prismarine-physics": "^1.7.0",
@@ -1,11 +0,0 @@
1
- FROM gitpod/workspace-full:latest
2
-
3
- RUN bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh \
4
- && sdk install java"
5
-
6
- RUN bash -c ". .nvm/nvm.sh \
7
- && nvm install 14 \
8
- && nvm use 14 \
9
- && nvm alias default 14"
10
-
11
- RUN echo "nvm use default &>/dev/null" >> ~/.bashrc.d/51-nvm-fix