spectra-physics 1.1.0 → 1.2.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.
@@ -85,6 +85,19 @@ function installServerHandlers (ctx) {
85
85
  state.boat = null
86
86
  bot.emit('dismount', vehicle)
87
87
  })
88
+
89
+ // the passenger list replaces the old one; mineflayer only appends and only leaves on vehicle id -1,
90
+ // which the server never sends, so a bot stays "mounted" after every dismount
91
+ client.on('set_passengers', ({ entityId, passengers }) => {
92
+ const vehicle = bot.entities[entityId]
93
+ if (vehicle) vehicle.passengers = passengers.map(id => bot.entities[id]).filter(Boolean)
94
+ const current = bot.vehicle
95
+ if (!current || current.id !== entityId || passengers.includes(bot.entity?.id)) return
96
+ bot.vehicle = null
97
+ if (bot.entity) bot.entity.vehicle = null
98
+ state.boat = null
99
+ bot.emit('dismount', current)
100
+ })
88
101
  }
89
102
 
90
103
  module.exports = { installServerHandlers }
@@ -1,10 +1,8 @@
1
1
  'use strict'
2
2
  // Minecraft#tick for the local player plus the timer that drives it.
3
3
 
4
- const { performance } = require('perf_hooks')
4
+ const { startTicking, stopTicking } = require('./clock')
5
5
 
6
- const TICK_MS = 50
7
- const MAX_CATCH_UP = 10
8
6
  const LOAD_TIMEOUT_TICKS = 60
9
7
  const MAX_TURN_DELAY = 40
10
8
 
@@ -67,12 +65,14 @@ function installTicker (ctx) {
67
65
  }
68
66
  if (bot.isAlive === false) return
69
67
  player.riding = false
68
+ ctx.updateItemUse()
70
69
  // 1.17 - 1.18.1: a turn while creeping through the air can't be reported cleanly, the mouse waits a moment
71
70
  if (state.creeping && state.turnDelay < MAX_TURN_DELAY) state.turnDelay++
72
71
  else {
73
72
  ctx.turn(state.turnDelay >= MAX_TURN_DELAY ? Infinity : undefined)
74
73
  state.turnDelay = 0
75
74
  }
75
+ ctx.flushActions()
76
76
  if (bot.physicsEnabled) {
77
77
  player.tick(ctx.keys())
78
78
  if (player.events.abilitiesChanged) {
@@ -102,25 +102,13 @@ function installTicker (ctx) {
102
102
  state.boat = null
103
103
  playerTick()
104
104
  }
105
+ ctx.flushActions()
105
106
  if (V.tickEnd) ctx.send('tick_end', {})
106
107
  bot.emit('physicsTick')
107
108
  }
108
109
 
109
- let timer = null
110
- let nextAt = 0
111
- function start () {
112
- if (timer) return
113
- nextAt = performance.now() + TICK_MS
114
- const loop = () => {
115
- const now = performance.now()
116
- for (let n = 0; now >= nextAt && n < MAX_CATCH_UP; n++) {
117
- try { clientTick() } catch (err) { bot.emit('error', err) }
118
- nextAt += TICK_MS
119
- }
120
- if (now - nextAt > 1000) nextAt = now + TICK_MS
121
- timer = setTimeout(loop, Math.max(0, nextAt - performance.now()))
122
- }
123
- timer = setTimeout(loop, TICK_MS)
110
+ const tick = () => {
111
+ try { clientTick() } catch (err) { bot.emit('error', err) }
124
112
  }
125
113
 
126
114
  client.on('login', () => {
@@ -129,14 +117,11 @@ function installTicker (ctx) {
129
117
  state.selectedSlot = 0
130
118
  state.carriedSlot = 0
131
119
  resetPlayer()
132
- start()
120
+ startTicking(tick)
133
121
  })
134
122
  client.on('respawn', resetPlayer)
135
123
  client.on('start_configuration', () => { state.inLevel = false })
136
- bot.on('end', () => {
137
- clearTimeout(timer)
138
- timer = null
139
- })
124
+ bot.on('end', () => stopTicking(tick))
140
125
 
141
126
  resetPlayer()
142
127
  }
@@ -34,9 +34,11 @@ class AABB {
34
34
 
35
35
  // strict positive-volume intersection (Shapes.joinIsNotEmpty(..., AND))
36
36
  intersectsBox (b) {
37
- return b[0] < this.maxX && b[3] > this.minX &&
38
- b[1] < this.maxY && b[4] > this.minY &&
39
- b[2] < this.maxZ && b[5] > this.minZ
37
+ return this.intersects(b[0], b[1], b[2], b[3], b[4], b[5])
38
+ }
39
+
40
+ intersects (minX, minY, minZ, maxX, maxY, maxZ) {
41
+ return minX < this.maxX && maxX > this.minX && minY < this.maxY && maxY > this.minY && minZ < this.maxZ && maxZ > this.minZ
40
42
  }
41
43
 
42
44
  min (axis) { return axis === 0 ? this.minX : (axis === 1 ? this.minY : this.minZ) }
@@ -18,12 +18,14 @@ class BoatPhysics {
18
18
  this.yRot = entity.yawDegrees ?? 0
19
19
  this.xRot = 0
20
20
  this.deltaRotation = 0
21
- this.status = 'IN_AIR'
22
- this.oldStatus = 'IN_AIR'
23
21
  this.landFriction = 0
24
22
  this.waterLevel = 0
23
+ this.lastYd = 0
25
24
  this.onGround = false
26
25
  this.paddle = [false, false]
26
+ // the boat already ticked its status before this client took control
27
+ this.status = this.getStatus()
28
+ this.oldStatus = this.status
27
29
  }
28
30
 
29
31
  bb () {
@@ -57,6 +59,42 @@ class BoatPhysics {
57
59
  return n > 0 ? f32(sum / n) : 0
58
60
  }
59
61
 
62
+ // Boat#isUnderwater
63
+ underwater () {
64
+ const bb = this.bb()
65
+ const top = bb.maxY + 0.001
66
+ let under = false
67
+ for (let x = Math.floor(bb.minX); x < Math.ceil(bb.maxX); x++) {
68
+ for (let y = Math.floor(bb.maxY); y < Math.ceil(top); y++) {
69
+ for (let z = Math.floor(bb.minZ); z < Math.ceil(bb.maxZ); z++) {
70
+ const fl = this.world.fluidAt(x, y, z)
71
+ if (!fl || fl.type !== 'water' || !(top < y + this.world.fluidHeight(x, y, z, fl))) continue
72
+ if (!fl.source) return 'UNDER_FLOWING_WATER'
73
+ under = true
74
+ }
75
+ }
76
+ }
77
+ return under ? 'UNDER_WATER' : null
78
+ }
79
+
80
+ // Boat#getWaterLevelAbove
81
+ waterLevelAbove () {
82
+ const bb = this.bb()
83
+ const top = Math.ceil(bb.maxY - this.lastYd)
84
+ for (let y = Math.floor(bb.maxY); y < top; y++) {
85
+ let level = 0
86
+ for (let x = Math.floor(bb.minX); x < Math.ceil(bb.maxX) && level < 1; x++) {
87
+ for (let z = Math.floor(bb.minZ); z < Math.ceil(bb.maxZ); z++) {
88
+ const fl = this.world.fluidAt(x, y, z)
89
+ if (fl && fl.type === 'water') level = Math.max(level, this.world.fluidHeight(x, y, z, fl))
90
+ if (level >= 1) break
91
+ }
92
+ }
93
+ if (level < 1) return f32(y + level)
94
+ }
95
+ return top + 1
96
+ }
97
+
60
98
  inWater () {
61
99
  const bb = this.bb()
62
100
  const x0 = Math.floor(bb.minX); const x1 = Math.ceil(bb.maxX)
@@ -69,7 +107,7 @@ class BoatPhysics {
69
107
  for (let z = z0; z < z1; z++) {
70
108
  const fl = this.world.fluidAt(x, y, z)
71
109
  if (fl && fl.type === 'water') {
72
- const top = y + this.world.fluidHeight(x, y, z, fl)
110
+ const top = f32(y + this.world.fluidHeight(x, y, z, fl))
73
111
  this.waterLevel = Math.max(top, this.waterLevel)
74
112
  found = found || bb.minY < top
75
113
  }
@@ -80,6 +118,11 @@ class BoatPhysics {
80
118
  }
81
119
 
82
120
  getStatus () {
121
+ const under = this.underwater()
122
+ if (under) {
123
+ this.waterLevel = this.bb().maxY
124
+ return under
125
+ }
83
126
  if (this.inWater()) return 'IN_WATER'
84
127
  const f = this.groundFriction()
85
128
  if (f > 0) { this.landFriction = f; return 'ON_LAND' }
@@ -89,16 +132,22 @@ class BoatPhysics {
89
132
  floatBoat () {
90
133
  let d2 = 0
91
134
  let inv = f32(0.05)
135
+ let gravity = G
92
136
  if (this.oldStatus === 'IN_AIR' && this.status !== 'IN_AIR' && this.status !== 'ON_LAND') {
93
- this.pos.y = this.waterLevel - BOAT_H + 0.101
94
- this.vel.y = 0
137
+ this.waterLevel = this.pos.y + BOAT_H
138
+ const y = this.waterLevelAbove() - BOAT_H + 0.101
139
+ if (this.world.noCollision(this.bb().move(0, y - this.pos.y, 0))) {
140
+ this.pos.y = y
141
+ this.vel.y = 0
142
+ this.lastYd = 0
143
+ }
95
144
  this.status = 'IN_WATER'
96
145
  return
97
146
  }
98
- if (this.status === 'IN_WATER') { d2 = (this.waterLevel - this.pos.y) / BOAT_H; inv = f32(0.9) } else if (this.status === 'IN_AIR') inv = f32(0.9)
147
+ if (this.status === 'IN_WATER') { d2 = (this.waterLevel - this.pos.y) / BOAT_H; inv = f32(0.9) } else if (this.status === 'UNDER_FLOWING_WATER') { gravity = -7.0e-4; inv = f32(0.9) } else if (this.status === 'UNDER_WATER') { d2 = f32(0.01); inv = f32(0.45) } else if (this.status === 'IN_AIR') inv = f32(0.9)
99
148
  else if (this.status === 'ON_LAND') { inv = this.landFriction; this.landFriction = f32(this.landFriction / 2) }
100
149
  this.vel.x *= inv
101
- this.vel.y += G
150
+ this.vel.y += gravity
102
151
  this.vel.z *= inv
103
152
  this.deltaRotation = f32(this.deltaRotation * inv)
104
153
  if (d2 > 0) this.vel.y = (this.vel.y + d2 * 0.06153846016296973) * 0.75
@@ -125,6 +174,7 @@ class BoatPhysics {
125
174
  this.controlBoat(keys)
126
175
  const collide = this.V.modernStepUp ? collideModern : collideLegacy
127
176
  const r = collide(this.world, this.vel.x, this.vel.y, this.vel.z, this.bb(), this.onGround, 0)
177
+ this.lastYd = this.vel.y
128
178
  if (r.x * r.x + r.y * r.y + r.z * r.z > 1.0e-7) { this.pos.x += r.x; this.pos.y += r.y; this.pos.z += r.z }
129
179
  const vertical = this.vel.y !== r.y
130
180
  this.onGround = vertical && this.vel.y < 0
@@ -1,14 +1,12 @@
1
1
  'use strict'
2
2
 
3
- const AABB = require('../aabb')
4
3
  const { f32 } = require('../mth')
4
+ const { traverseMoves, BlockList } = require('./traversal')
5
5
 
6
6
  const F_098 = f32(0.98)
7
7
  const F_08 = f32(0.8)
8
8
  const F_09 = f32(0.9)
9
9
  const F_005 = f32(0.05)
10
- const F_1EM5 = f32(1.0e-5)
11
- const LONG_MOVE = f32(0.99999) * f32(0.99999)
12
10
  const HALF_WIDTH = f32(0.3)
13
11
 
14
12
  const STUCK = {
@@ -69,6 +67,8 @@ function onInsideBlock (player, block, bx, by, bz, withVelocityEffects) {
69
67
  }
70
68
  }
71
69
 
70
+ const visited = new BlockList()
71
+
72
72
  function forEachBlockIn (box, visit) {
73
73
  const x0 = Math.floor(box.minX); const x1 = Math.floor(box.maxX)
74
74
  const y0 = Math.floor(box.minY); const y1 = Math.floor(box.maxY)
@@ -94,57 +94,20 @@ function checkInsideBlocksLegacy (player) {
94
94
  settleStuck(player)
95
95
  }
96
96
 
97
- // voxel walk of the box corner between two points, used for moves longer than a block
98
- function blocksAlongTravel (from, to, box, out) {
99
- const dx = to.x - from.x; const dy = to.y - from.y; const dz = to.z - from.z
100
- const start = { x: box.minX - dx, y: box.minY - dy, z: box.minZ - dz }
101
- let cx = Math.floor(start.x); let cy = Math.floor(start.y); let cz = Math.floor(start.z)
102
- const sx = Math.sign(dx); const sy = Math.sign(dy); const sz = Math.sign(dz)
103
- const tx = sx === 0 ? Infinity : sx / dx
104
- const ty = sy === 0 ? Infinity : sy / dy
105
- const tz = sz === 0 ? Infinity : sz / dz
106
- const frac = (v) => v - Math.floor(v)
107
- let nx = tx * (sx > 0 ? 1 - frac(start.x) : frac(start.x))
108
- let ny = ty * (sy > 0 ? 1 - frac(start.y) : frac(start.y))
109
- let nz = tz * (sz > 0 ? 1 - frac(start.z) : frac(start.z))
110
- const sizeX = box.maxX - box.minX; const sizeY = box.maxY - box.minY; const sizeZ = box.maxZ - box.minZ
111
- for (let steps = 0; (nx <= 1 || ny <= 1 || nz <= 1) && steps <= 16; steps++) {
112
- if (nx < ny) {
113
- if (nx < nz) { cx += sx; nx += tx } else { cz += sz; nz += tz }
114
- } else if (ny < nz) { cy += sy; ny += ty } else { cz += sz; nz += tz }
115
- forEachBlockIn(new AABB(cx, cy, cz, cx + sizeX, cy + sizeY, cz + sizeZ), (x, y, z) => out.add(`${x},${y},${z}`))
116
- }
117
- }
118
-
119
97
  // Entity#applyEffectsFromBlocks, 1.21.2+: after travel, along every movement made this tick
120
98
  function applyEffectsAfterTravel (player) {
121
99
  if (!player.V.blockEffectsAfterTravel) return
122
100
  player.stuck = null
123
- const end = { ...player.pos }
124
- const moves = player.V.blockEffectsPerAxis && player.movesThisTick.length ? [...player.movesThisTick] : [{ from: player.tickStart, to: end }]
101
+ const end = { x: player.pos.x, y: player.pos.y, z: player.pos.z }
102
+ const moves = player.V.blockEffectsPerAxis && player.movesThisTick.length ? player.movesThisTick.slice() : [{ from: player.tickStart, to: end, input: null }]
125
103
  const last = moves[moves.length - 1].to
126
- if ((last.x - end.x) ** 2 + (last.y - end.y) ** 2 + (last.z - end.z) ** 2 > 9.9999994e-11) moves.push({ from: last, to: end })
127
- const visited = new Set()
128
- for (const { from, to } of moves) {
129
- const endBox = player.bbAt(to.x, to.y, to.z).deflate(F_1EM5)
130
- const keys = new Set()
131
- forEachBlockIn(endBox, (x, y, z) => keys.add(`${x},${y},${z}`))
132
- const lengthSq = (to.x - from.x) ** 2 + (to.y - from.y) ** 2 + (to.z - from.z) ** 2
133
- const far = lengthSq >= LONG_MOVE
134
- if (player.V.blockEffectsPerAxis && lengthSq > 0) {
135
- forEachBlockIn(player.bbAt(from.x, from.y, from.z).deflate(F_1EM5), (x, y, z) => keys.add(`${x},${y},${z}`))
136
- }
137
- if (far) blocksAlongTravel(from, to, endBox, keys)
138
- for (const key of keys) {
139
- if (visited.has(key)) continue
140
- visited.add(key)
141
- const [x, y, z] = key.split(',').map(Number)
142
- const block = player.world.blockAt(x, y, z)
143
- if (block.isAir) continue
144
- const inEndBox = endBox.intersectsBox([x, y, z, x + 1, y + 1, z + 1])
145
- onInsideBlock(player, block, x, y, z, far || inEndBox)
146
- }
147
- }
104
+ if ((last.x - end.x) ** 2 + (last.y - end.y) ** 2 + (last.z - end.z) ** 2 > 9.9999994e-11) moves.push({ from: last, to: end, input: null })
105
+ visited.clear()
106
+ traverseMoves(player, moves, (x, y, z, applyVelocity) => {
107
+ const block = player.world.blockAt(x, y, z)
108
+ if (block.isAir || !visited.add(x, y, z)) return
109
+ onInsideBlock(player, block, x, y, z, applyVelocity)
110
+ })
148
111
  player.movesThisTick.length = 0
149
112
  settleStuck(player)
150
113
  }
@@ -105,7 +105,19 @@ function updateEyes (player) {
105
105
  const by = Math.floor(eyeY)
106
106
  const bz = Math.floor(player.pos.z)
107
107
  const fluid = player.world.fluidAt(bx, by, bz)
108
- player.eyeInWater = !!(fluid && fluid.type === 'water' && by + player.world.fluidHeight(bx, by, bz, fluid) > eyeY)
108
+ const top = fluid && fluid.type === 'water' ? by + player.world.fluidHeight(bx, by, bz, fluid) : -Infinity
109
+ // 26.1 EntityFluidInteraction counts the surface itself as inside
110
+ player.eyeInWater = player.V.fluidInteraction ? top >= eyeY : top > eyeY
111
+ }
112
+
113
+ const lavaPush = (player) => player.env.ultraWarm() ? 0.007 : 0.0023333333333333335
114
+
115
+ // 26.1 Entity#updateFluidInteraction: water and lava together
116
+ function updateFluidInteraction (player) {
117
+ player.fluidHeight.water = 0
118
+ player.fluidHeight.lava = 0
119
+ updateWater(player)
120
+ touchFluid(player, 'lava', lavaPush(player))
109
121
  }
110
122
 
111
123
  // Player#updateSwimming
@@ -122,10 +134,7 @@ function updateSwimming (player) {
122
134
  }
123
135
 
124
136
  function updateFluids (player) {
125
- player.fluidHeight.water = 0
126
- player.fluidHeight.lava = 0
127
- updateWater(player)
128
- touchFluid(player, 'lava', player.env.ultraWarm() ? 0.007 : 0.0023333333333333335)
137
+ updateFluidInteraction(player)
129
138
  updateEyes(player)
130
139
  updateSwimming(player)
131
140
  }
@@ -138,4 +147,4 @@ function fluidFallingAdjusted (player, gravity, falling) {
138
147
  else player.vel.y = vy - gravity / 16
139
148
  }
140
149
 
141
- module.exports = { updateFluids, updateWater, fluidFallingAdjusted }
150
+ module.exports = { updateFluids, updateWater, updateFluidInteraction, fluidFallingAdjusted }
@@ -34,6 +34,13 @@ class PlayerPhysics {
34
34
  this.world = world
35
35
  this.V = V
36
36
  this.env = { ...DEFAULT_ENV, ...env }
37
+ const player = this
38
+ this.collisionContext = {
39
+ get bottom () { return player.pos.y },
40
+ get fallDistance () { return player.fallDistance },
41
+ get walksOnPowderSnow () { return player.V.powderSnow && player.env.bootsItem() === 'leather_boots' },
42
+ get descending () { return player.input.shift }
43
+ }
37
44
  this.reset()
38
45
  }
39
46
 
@@ -94,7 +101,18 @@ class PlayerPhysics {
94
101
  }
95
102
 
96
103
  tick (keys) {
97
- this.tickStart = { ...this.pos }
104
+ this.world.beginTick(this.collisionContext)
105
+ try {
106
+ this.tickInner(keys)
107
+ } finally {
108
+ this.world.endTick()
109
+ }
110
+ }
111
+
112
+ tickInner (keys) {
113
+ this.tickStart.x = this.pos.x
114
+ this.tickStart.y = this.pos.y
115
+ this.tickStart.z = this.pos.z
98
116
  this.movesThisTick.length = 0
99
117
  this.baseTick()
100
118
 
@@ -9,6 +9,8 @@ const F_MIN_LENGTH = f32(1.0e-4)
9
9
 
10
10
  const impulse = (positive, negative) => positive === negative ? 0 : (positive ? 1 : -1)
11
11
 
12
+ const slowedByItem = (player) => player.env.usingItem() && !player.riding
13
+
12
14
  function sneakMultiplier (player) {
13
15
  return player.V.efficiencyAttributes ? f32(player.env.attribute('sneaking_speed', 0.3)) : F_03
14
16
  }
@@ -21,7 +23,7 @@ function legacyInput (player, left, forward, slow) {
21
23
  const k = sneakMultiplier(player)
22
24
  x = f32(x * k); z = f32(z * k)
23
25
  }
24
- if (player.env.usingItem()) { x = f32(x * F_02); z = f32(z * F_02) }
26
+ if (slowedByItem(player)) { x = f32(x * F_02); z = f32(z * F_02) }
25
27
  return [f32(x * F_098), f32(z * F_098)]
26
28
  }
27
29
 
@@ -31,7 +33,7 @@ function modernInput (player, left, forward, slow) {
31
33
  if (length < F_MIN_LENGTH) return [0, 0]
32
34
  let x = f32(f32(left / length) * F_098)
33
35
  let z = f32(f32(forward / length) * F_098)
34
- if (player.env.usingItem()) { x = f32(x * F_02); z = f32(z * F_02) }
36
+ if (slowedByItem(player)) { x = f32(x * F_02); z = f32(z * F_02) }
35
37
  if (slow) {
36
38
  const k = sneakMultiplier(player)
37
39
  x = f32(x * k); z = f32(z * k)
@@ -54,6 +56,7 @@ function readKeys (player, keys, slow) {
54
56
  const [xxa, zza] = player.V.inputModel === 'modern'
55
57
  ? modernInput(player, left, forward, slow)
56
58
  : legacyInput(player, left, forward, slow)
59
+ if (slowedByItem(player)) player.sprintTriggerTime = 0
57
60
  player.input = {
58
61
  left: xxa,
59
62
  forward: zza,
@@ -4,7 +4,7 @@ const { f32, sin, cos, degToRadF, equal } = require('../mth')
4
4
  const { collideLegacy, collideModern } = require('../collision')
5
5
  const { onPos, speedFactor, updateSupportingBlock } = require('./blocks')
6
6
  const { checkInsideBlocksLegacy } = require('./effects')
7
- const { updateWater } = require('./fluids')
7
+ const { updateWater, updateFluidInteraction } = require('./fluids')
8
8
 
9
9
  const F_066 = f32(0.66)
10
10
  const F_1EM5 = f32(1.0e-5)
@@ -78,9 +78,12 @@ function zeroBlockedAxes (player, vx, vz, r) {
78
78
  return
79
79
  }
80
80
  // 1.14 - 1.18.1: the second write restores X when both axes are blocked
81
- const before = { ...player.vel }
82
- if (vx !== r.x) player.vel = { x: 0, y: before.y, z: before.z }
83
- if (vz !== r.z) player.vel = { x: V.keepsXOnCornerCollision ? before.x : player.vel.x, y: before.y, z: 0 }
81
+ const x = player.vel.x
82
+ if (vx !== r.x) player.vel.x = 0
83
+ if (vz !== r.z) {
84
+ if (V.keepsXOnCornerCollision) player.vel.x = x
85
+ player.vel.z = 0
86
+ }
84
87
  }
85
88
 
86
89
  // Entity#move(MoverType.SELF, movement)
@@ -95,7 +98,7 @@ function move (player, mx, my, mz) {
95
98
  mx = bx; mz = bz
96
99
 
97
100
  const bb = player.bb()
98
- const from = { ...player.pos }
101
+ const from = V.blockEffectsPerAxis ? { ...player.pos } : null
99
102
  const collide = V.modernStepUp ? collideModern : collideLegacy
100
103
  const r = collide(player.world, mx, my, mz, bb, player.onGround, player.maxUpStep())
101
104
  const lengthSq = r.x * r.x + r.y * r.y + r.z * r.z
@@ -111,7 +114,10 @@ function move (player, mx, my, mz) {
111
114
  player.onGround = player.verticalCollision && my < 0
112
115
  updateSupportingBlock(player, player.onGround, r.x, r.z)
113
116
 
114
- if (V.fluidRecheckInMove && !player.wasTouchingWater && !player.riding) updateWater(player)
117
+ if (V.fluidRecheckInMove && !player.wasTouchingWater && !player.riding) {
118
+ if (V.fluidInteraction) updateFluidInteraction(player)
119
+ else updateWater(player)
120
+ }
115
121
  if (player.onGround) {
116
122
  player.fallDistance = 0
117
123
  } else if (r.y < 0) {
@@ -124,7 +130,7 @@ function move (player, mx, my, mz) {
124
130
  if (my !== r.y) landOn(player, block)
125
131
  if (player.onGround && !player.input.shift) stepOn(player, block)
126
132
 
127
- if (V.blockEffectsPerAxis && applies) player.movesThisTick.push({ from, to: { ...player.pos } })
133
+ if (V.blockEffectsPerAxis && applies) player.movesThisTick.push({ from, to: { ...player.pos }, input: { x: mx, y: my, z: mz } })
128
134
  if (!V.blockEffectsAfterTravel) checkInsideBlocksLegacy(player)
129
135
 
130
136
  const factor = speedFactor(player)
@@ -49,7 +49,7 @@ function suffocatesAt (player, bx, bz) {
49
49
  const block = player.world.blockAt(x, y, z)
50
50
  if (!block.suffocating) continue
51
51
  for (const s of block.shapes) {
52
- if (box.intersectsBox([s[0] + x, s[1] + y, s[2] + z, s[3] + x, s[4] + y, s[5] + z])) return true
52
+ if (box.intersects(s[0] + x, s[1] + y, s[2] + z, s[3] + x, s[4] + y, s[5] + z)) return true
53
53
  }
54
54
  }
55
55
  }