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.
@@ -0,0 +1,290 @@
1
+ 'use strict'
2
+ // Which blocks Entity#applyEffectsFromBlocks visits after travel (1.21.2+), and in what order. The order
3
+ // matters: effects such as bubble columns depend on the velocity left by the blocks visited before them.
4
+ // Each client version walks the movement differently; the four variants below follow those versions.
5
+
6
+ const { f32 } = require('../mth')
7
+
8
+ const EPS = 1.0e-7
9
+ const DEFLATE = f32(1.0e-5)
10
+ const SHORT_MOVE_SQ = f32(f32(0.99999) * f32(0.99999))
11
+ const TINY_MOVE_SQ = DEFLATE * DEFLATE
12
+ const FAR_SQ = 0.9999900000002526 * 0.9999900000002526
13
+ const STEP_LIMIT = 16
14
+
15
+ // insertion-ordered set of block positions, small enough that a linear scan beats hashing
16
+ class BlockList {
17
+ constructor () { this.coords = []; this.length = 0 }
18
+
19
+ clear () { this.length = 0; return this }
20
+
21
+ has (x, y, z) {
22
+ const c = this.coords
23
+ for (let i = 0; i < this.length * 3; i += 3) if (c[i] === x && c[i + 1] === y && c[i + 2] === z) return true
24
+ return false
25
+ }
26
+
27
+ // true when the position was not in the list yet
28
+ add (x, y, z) {
29
+ if (this.has(x, y, z)) return false
30
+ const i = this.length * 3
31
+ this.coords[i] = x; this.coords[i + 1] = y; this.coords[i + 2] = z
32
+ this.length++
33
+ return true
34
+ }
35
+
36
+ forEach (visit) {
37
+ const c = this.coords
38
+ for (let i = 0; i < this.length * 3; i += 3) visit(c[i], c[i + 1], c[i + 2])
39
+ }
40
+ }
41
+
42
+ const seenAlong = new BlockList()
43
+ const seenBetween = new BlockList()
44
+ const ordered = new BlockList()
45
+
46
+ const frac = (v) => v - Math.floor(v)
47
+ const sign = (v) => v === 0 ? 0 : (v > 0 ? 1 : -1)
48
+
49
+ // BlockPos.betweenClosed: x fastest, then y, then z
50
+ function forEachBetweenClosed (box, visit) {
51
+ const x0 = Math.floor(box.minX); const y0 = Math.floor(box.minY); const z0 = Math.floor(box.minZ)
52
+ const x1 = Math.floor(box.maxX); const y1 = Math.floor(box.maxY); const z1 = Math.floor(box.maxZ)
53
+ for (let z = z0; z <= z1; z++) {
54
+ for (let y = y0; y <= y1; y++) {
55
+ for (let x = x0; x <= x1; x++) visit(x, y, z)
56
+ }
57
+ }
58
+ }
59
+
60
+ // Y first, then the smaller of x/z ... matching Direction.axisStepOrder
61
+ const axisStepOrder = (v) => Math.abs(v.x) < Math.abs(v.z) ? 'yzx' : 'yxz'
62
+
63
+ // BlockPos.betweenCornersInDirection: starts at the corner facing away from the direction,
64
+ // walks Y, then the smaller of x/z, then the other one (innermost)
65
+ function forEachBetweenCorners (ax, ay, az, bx, by, bz, dir, visit) {
66
+ const minX = Math.min(ax, bx); const minY = Math.min(ay, by); const minZ = Math.min(az, bz)
67
+ const sizeX = Math.max(ax, bx) - minX; const sizeY = Math.max(ay, by) - minY; const sizeZ = Math.max(az, bz) - minZ
68
+ const sx = dir.x >= 0 ? 1 : -1; const sy = dir.y >= 0 ? 1 : -1; const sz = dir.z >= 0 ? 1 : -1
69
+ const x0 = sx > 0 ? minX : minX + sizeX; const y0 = sy > 0 ? minY : minY + sizeY; const z0 = sz > 0 ? minZ : minZ + sizeZ
70
+ const zSecond = Math.abs(dir.x) < Math.abs(dir.z)
71
+ for (let i = 0; i <= sizeY; i++) {
72
+ const y = y0 + sy * i
73
+ if (zSecond) {
74
+ for (let j = 0; j <= sizeZ; j++) {
75
+ const z = z0 + sz * j
76
+ for (let k = 0; k <= sizeX; k++) if (visit(x0 + sx * k, y, z) === false) return false
77
+ }
78
+ } else {
79
+ for (let j = 0; j <= sizeX; j++) {
80
+ const x = x0 + sx * j
81
+ for (let k = 0; k <= sizeZ; k++) if (visit(x, y, z0 + sz * k) === false) return false
82
+ }
83
+ }
84
+ }
85
+ return true
86
+ }
87
+
88
+ function clipPoint (best, delta, side, startSide, minA, maxA, minB, maxB, startA, deltaA, startB, deltaB) {
89
+ const t = (side - startSide) / delta
90
+ const a = startA + t * deltaA
91
+ const b = startB + t * deltaB
92
+ if (t > 0 && t < best.t && minA - EPS < a && a < maxA + EPS && minB - EPS < b && b < maxB + EPS) {
93
+ best.t = t
94
+ best.hit = true
95
+ }
96
+ }
97
+
98
+ // AABB.clip of the unit cube at (x, y, z) against the segment start -> end
99
+ function clip (x, y, z, start, end) {
100
+ const dx = end.x - start.x; const dy = end.y - start.y; const dz = end.z - start.z
101
+ const best = { t: 1, hit: false }
102
+ if (dx > EPS) clipPoint(best, dx, x, start.x, y, y + 1, z, z + 1, start.y, dy, start.z, dz)
103
+ else if (dx < -EPS) clipPoint(best, dx, x + 1, start.x, y, y + 1, z, z + 1, start.y, dy, start.z, dz)
104
+ if (dy > EPS) clipPoint(best, dy, y, start.y, z, z + 1, x, x + 1, start.z, dz, start.x, dx)
105
+ else if (dy < -EPS) clipPoint(best, dy, y + 1, start.y, z, z + 1, x, x + 1, start.z, dz, start.x, dx)
106
+ if (dz > EPS) clipPoint(best, dz, z, start.z, x, x + 1, y, y + 1, start.x, dx, start.y, dy)
107
+ else if (dz < -EPS) clipPoint(best, dz, z + 1, start.z, x, x + 1, y, y + 1, start.x, dx, start.y, dy)
108
+ return best.hit ? { x: start.x + best.t * dx, y: start.y + best.t * dy, z: start.z + best.t * dz } : null
109
+ }
110
+
111
+ // voxel walk of one corner of the box from start to end; calls hit(cx, cy, cz, point, step) on every cell it enters
112
+ function walk (start, end, limited, hit) {
113
+ const d = { x: end.x - start.x, y: end.y - start.y, z: end.z - start.z }
114
+ let cx = Math.floor(start.x); let cy = Math.floor(start.y); let cz = Math.floor(start.z)
115
+ const sx = sign(d.x); const sy = sign(d.y); const sz = sign(d.z)
116
+ const tx = sx === 0 ? Number.MAX_VALUE : sx / d.x
117
+ const ty = sy === 0 ? Number.MAX_VALUE : sy / d.y
118
+ const tz = sz === 0 ? Number.MAX_VALUE : sz / d.z
119
+ let nx = tx * (sx > 0 ? 1 - frac(start.x) : frac(start.x))
120
+ let ny = ty * (sy > 0 ? 1 - frac(start.y) : frac(start.y))
121
+ let nz = tz * (sz > 0 ? 1 - frac(start.z) : frac(start.z))
122
+ let steps = 0
123
+ while (nx <= 1 || ny <= 1 || nz <= 1) {
124
+ if (nx < ny) {
125
+ if (nx < nz) { cx += sx; nx += tx } else { cz += sz; nz += tz }
126
+ } else if (ny < nz) { cy += sy; ny += ty } else { cz += sz; nz += tz }
127
+ if (limited && steps++ > STEP_LIMIT) break
128
+ const point = clip(cx, cy, cz, start, end)
129
+ if (!point) continue
130
+ if (!limited) steps++
131
+ if (hit(cx, cy, cz, point, steps) === false) return -1
132
+ }
133
+ return steps
134
+ }
135
+
136
+ const clamp = (v, lo, hi) => v < lo ? lo : (v > hi ? hi : v)
137
+ const clampInto = (point, cx, cy, cz) => ({
138
+ x: clamp(point.x, cx + DEFLATE, cx + 1 - DEFLATE),
139
+ y: clamp(point.y, cy + DEFLATE, cy + 1 - DEFLATE),
140
+ z: clamp(point.z, cz + DEFLATE, cz + 1 - DEFLATE)
141
+ })
142
+
143
+ // 1.21.2 - 1.21.8: the min corner of the box walks the movement; every cell hit adds a box-sized block range
144
+ function legacyAlongTravel (box, direction, nudge, visit) {
145
+ const len = Math.sqrt(direction.x ** 2 + direction.y ** 2 + direction.z ** 2)
146
+ const n = nudge ? { x: direction.x / len * EPS, y: direction.y / len * EPS, z: direction.z / len * EPS } : { x: 0, y: 0, z: 0 }
147
+ const end = { x: box.minX + n.x, y: box.minY + n.y, z: box.minZ + n.z }
148
+ const start = { x: box.minX - direction.x - n.x, y: box.minY - direction.y - n.y, z: box.minZ - direction.z - n.z }
149
+ const sizeX = box.maxX - box.minX; const sizeY = box.maxY - box.minY; const sizeZ = box.maxZ - box.minZ
150
+ return walk(start, end, true, (cx, cy, cz, point, step) => {
151
+ const c = clampInto(point, cx, cy, cz)
152
+ const ex = Math.floor(c.x + sizeX); const ey = Math.floor(c.y + sizeY); const ez = Math.floor(c.z + sizeZ)
153
+ for (let x = cx; x <= ex; x++) {
154
+ for (let y = cy; y <= ey; y++) {
155
+ for (let z = cz; z <= ez; z++) visit(x, y, z, step)
156
+ }
157
+ }
158
+ })
159
+ }
160
+
161
+ // BlockCollisions#getFurthestCorner (1.21.10+)
162
+ function furthestCorner (v) {
163
+ const ax = Math.abs(v.x); const ay = Math.abs(v.y); const az = Math.abs(v.z)
164
+ const xs = v.x >= 0 ? 1 : -1; const ys = v.y >= 0 ? 1 : -1; const zs = v.z >= 0 ? 1 : -1
165
+ if (ax <= ay && ax <= az) return { x: -xs, y: -zs, z: ys }
166
+ return ay <= az ? { x: zs, y: -ys, z: -xs } : { x: -ys, y: xs, z: -zs }
167
+ }
168
+
169
+ // 1.21.9+: BlockGetter#forEachBlockIntersectedBetween
170
+ function modernBetween (from, to, box, visit) {
171
+ const d = { x: to.x - from.x, y: to.y - from.y, z: to.z - from.z }
172
+ if (d.x * d.x + d.y * d.y + d.z * d.z < TINY_MOVE_SQ) {
173
+ forEachBetweenClosed(box, (x, y, z) => visit(x, y, z, 0))
174
+ return
175
+ }
176
+ const seen = seenBetween.clear()
177
+ const back = box.move(-d.x, -d.y, -d.z)
178
+ const ok = forEachBetweenCorners(Math.floor(back.minX), Math.floor(back.minY), Math.floor(back.minZ),
179
+ Math.floor(back.maxX), Math.floor(back.maxY), Math.floor(back.maxZ), d, (x, y, z) => {
180
+ if (visit(x, y, z, 0) === false) return false
181
+ seen.add(x, y, z)
182
+ })
183
+ if (!ok) return
184
+ const sizeX = box.maxX - box.minX; const sizeY = box.maxY - box.minY; const sizeZ = box.maxZ - box.minZ
185
+ const corner = furthestCorner(d)
186
+ const center = { x: box.minX + 0.5 * sizeX, y: box.minY + 0.5 * sizeY, z: box.minZ + 0.5 * sizeZ }
187
+ const end = { x: center.x + sizeX * 0.5 * corner.x, y: center.y + sizeY * 0.5 * corner.y, z: center.z + sizeZ * 0.5 * corner.z }
188
+ const start = { x: end.x - d.x, y: end.y - d.y, z: end.z - d.z }
189
+ const steps = walk(start, end, false, (cx, cy, cz, point, step) => {
190
+ const c = clampInto(point, cx, cy, cz)
191
+ const ex = Math.floor(c.x - sizeX * corner.x); const ey = Math.floor(c.y - sizeY * corner.y); const ez = Math.floor(c.z - sizeZ * corner.z)
192
+ return forEachBetweenCorners(cx, cy, cz, ex, ey, ez, d, (x, y, z) => {
193
+ if (seen.add(x, y, z)) return visit(x, y, z, step)
194
+ })
195
+ })
196
+ if (steps < 0) return
197
+ forEachBetweenCorners(Math.floor(box.minX), Math.floor(box.minY), Math.floor(box.minZ),
198
+ Math.floor(box.maxX), Math.floor(box.maxY), Math.floor(box.maxZ), d, (x, y, z) => {
199
+ if (seen.add(x, y, z)) return visit(x, y, z, steps + 1)
200
+ })
201
+ }
202
+
203
+ /**
204
+ * Visits the blocks touched by this tick's movements in game order.
205
+ * moves: [{ from, to, input }] where input is the movement asked of Entity#move (1.21.5+), or null.
206
+ * visit(x, y, z, applyVelocity)
207
+ */
208
+ function traverseMoves (player, moves, visit) {
209
+ const pv = player.V.protocol
210
+ const boxAt = (p) => player.bbAt(p.x, p.y, p.z).deflate(DEFLATE)
211
+
212
+ if (pv < 769) { // 1.21.2 - 1.21.3: the final box, nudged walk
213
+ const box = player.bb().deflate(DEFLATE)
214
+ for (const { from, to } of moves) {
215
+ const d = { x: to.x - from.x, y: to.y - from.y, z: to.z - from.z }
216
+ if (d.x * d.x + d.y * d.y + d.z * d.z < SHORT_MOVE_SQ) {
217
+ forEachBetweenClosed(box, (x, y, z) => visit(x, y, z, true))
218
+ continue
219
+ }
220
+ const list = ordered.clear()
221
+ const add = (x, y, z) => { list.add(x, y, z) }
222
+ legacyAlongTravel(box, d, true, add)
223
+ forEachBetweenClosed(box, add)
224
+ list.forEach((x, y, z) => visit(x, y, z, true))
225
+ }
226
+ return
227
+ }
228
+
229
+ if (pv < 770) { // 1.21.4: box at the end of each movement
230
+ for (const { from, to } of moves) {
231
+ const box = boxAt(to)
232
+ const d = { x: to.x - from.x, y: to.y - from.y, z: to.z - from.z }
233
+ if (d.x * d.x + d.y * d.y + d.z * d.z < SHORT_MOVE_SQ) {
234
+ forEachBetweenClosed(box, (x, y, z) => visit(x, y, z, true))
235
+ continue
236
+ }
237
+ const list = ordered.clear()
238
+ const add = (x, y, z) => { list.add(x, y, z) }
239
+ legacyAlongTravel(box, d, false, add)
240
+ forEachBetweenClosed(box, add)
241
+ list.forEach((x, y, z) => visit(x, y, z, true))
242
+ }
243
+ return
244
+ }
245
+
246
+ const modern = pv >= 773
247
+ for (const move of moves) {
248
+ const delta = { x: move.to.x - move.from.x, y: move.to.y - move.from.y, z: move.to.z - move.from.z }
249
+ let budget = STEP_LIMIT
250
+ const segment = (from, to, limit) => {
251
+ const box = boxAt(to)
252
+ if (!modern) {
253
+ const d = { x: to.x - from.x, y: to.y - from.y, z: to.z - from.z }
254
+ if (d.x * d.x + d.y * d.y + d.z * d.z < SHORT_MOVE_SQ) {
255
+ forEachBetweenClosed(box, (x, y, z) => visit(x, y, z, true))
256
+ return 0
257
+ }
258
+ const seen = seenAlong.clear()
259
+ const steps = legacyAlongTravel(box, d, false, (x, y, z) => {
260
+ if (seen.add(x, y, z)) visit(x, y, z, true)
261
+ })
262
+ forEachBetweenClosed(box, (x, y, z) => { if (!seen.has(x, y, z)) visit(x, y, z, true) })
263
+ return steps
264
+ }
265
+ const far = (to.x - from.x) ** 2 + (to.y - from.y) ** 2 + (to.z - from.z) ** 2 > FAR_SQ
266
+ let reached = 0
267
+ modernBetween(from, to, box, (x, y, z, step) => {
268
+ if (step >= limit) return false
269
+ reached = step
270
+ visit(x, y, z, far || box.intersects(x, y, z, x + 1, y + 1, z + 1))
271
+ })
272
+ return reached + 1
273
+ }
274
+ if (move.input && (delta.x || delta.y || delta.z)) {
275
+ let from = move.from
276
+ for (const axis of axisStepOrder(modern ? move.input : delta)) {
277
+ const value = delta[axis]
278
+ if (value === 0) continue
279
+ const to = { ...from, [axis]: from[axis] + value }
280
+ budget -= segment(from, to, budget)
281
+ from = to
282
+ }
283
+ } else {
284
+ budget -= segment(move.from, move.to, STEP_LIMIT)
285
+ }
286
+ if (modern && budget <= 0) segment(move.to, move.to, 1)
287
+ }
288
+ }
289
+
290
+ module.exports = { traverseMoves, BlockList, forEachBetweenCorners, furthestCorner, clip }
@@ -15,7 +15,8 @@ const PV = {
15
15
  '1.21.4': 769,
16
16
  '1.21.5': 770,
17
17
  '1.21.6': 771,
18
- '1.21.9': 773
18
+ '1.21.9': 773,
19
+ '26.1': 775
19
20
  }
20
21
 
21
22
  function versionFlags (registry) {
@@ -67,6 +68,7 @@ function versionFlags (registry) {
67
68
  blockEffectsPerAxis: at('1.21.5'),
68
69
  insideBlockDeflate: at('1.19.4') ? 1.0e-5 : 0.001,
69
70
  fluidRecheckInMove: pv !== PV['1.21.4'],
71
+ fluidInteraction: at('26.1'), // one pass over water and lava, also used by the recheck in move
70
72
  swimmingNeedsFeetInWater: at('1.17'),
71
73
  powderSnow: at('1.17'),
72
74
 
@@ -14,37 +14,83 @@ const SPEED_FACTOR = { soul_sand: 0.4, honey_block: 0.4 }
14
14
  const JUMP_FACTOR = { honey_block: 0.5 }
15
15
 
16
16
  const FULL = [0, 0, 0, 1, 1, 1]
17
+ const NO_SHAPES = []
18
+ const SNOW_FULL = [FULL]
19
+ const SNOW_FALLING = [[0, 0, 0, 1, f32(0.9), 1]]
20
+ const ABOVE_EPSILON = f32(1.0e-5)
17
21
 
18
22
  class WorldView {
19
23
  constructor (bot) {
20
24
  this.bot = bot
21
25
  this.registry = bot.registry
22
26
  this.Block = require('prismarine-block')(bot.registry)
23
- this.cache = new Map()
27
+ let states = 1
28
+ for (const b of bot.registry.blocksArray ?? []) states = Math.max(states, (b.maxStateId ?? b.id) + 1)
29
+ this.infos = new Array(states).fill(null)
30
+ this.boxes = []
31
+ this.boxPool = []
24
32
  this.pos = { x: 0, y: 0, z: 0 }
33
+ // collision context of the entity that is moving: { bottom, fallDistance, walksOnPowderSnow, descending }
34
+ this.entity = null
35
+ // while an entity ticks nothing else can change the world, so column lookups are memoised
36
+ this.ticking = false
37
+ this.columns = new Map()
38
+ this.bottom = 0
39
+ this.top = 256
40
+ }
41
+
42
+ beginTick (entity = null) {
43
+ this.entity = entity
44
+ this.ticking = true
45
+ this.columns.clear()
46
+ this.bottom = this.minY
47
+ this.top = this.maxY
48
+ }
49
+
50
+ endTick () {
51
+ this.entity = null
52
+ this.ticking = false
53
+ }
54
+
55
+ column (cx, cz) {
56
+ if (!this.ticking) return this.bot.world.getColumn(cx, cz)
57
+ const key = cx * 4194304 + cz
58
+ let col = this.columns.get(key)
59
+ if (col === undefined) {
60
+ col = this.bot.world.getColumn(cx, cz) ?? null
61
+ this.columns.set(key, col)
62
+ }
63
+ return col
64
+ }
65
+
66
+ // PowderSnowBlock#getCollisionShape
67
+ powderSnowShapes (y) {
68
+ const e = this.entity
69
+ if (!e) return NO_SHAPES
70
+ if (e.fallDistance > 2.5) return SNOW_FALLING
71
+ if (e.walksOnPowderSnow && e.bottom > y + 1 - ABOVE_EPSILON && !e.descending) return SNOW_FULL
72
+ return NO_SHAPES
25
73
  }
26
74
 
27
75
  get minY () { return this.bot.game?.minY ?? 0 }
28
76
  get maxY () { return this.minY + (this.bot.game?.height ?? 256) }
29
77
 
30
78
  hasChunk (bx, bz) {
31
- return !!this.bot.world.getColumn(Math.floor(bx) >> 4, Math.floor(bz) >> 4)
79
+ return !!this.column(Math.floor(bx) >> 4, Math.floor(bz) >> 4)
32
80
  }
33
81
 
34
82
  // returns null when the column is not loaded
35
83
  stateAt (x, y, z) {
36
- const col = this.bot.world.getColumn(x >> 4, z >> 4)
84
+ const col = this.column(x >> 4, z >> 4)
37
85
  if (!col) return null
38
- if (y < this.minY || y >= this.maxY) return 0
86
+ if (this.ticking ? (y < this.bottom || y >= this.top) : (y < this.minY || y >= this.maxY)) return 0
39
87
  this.pos.x = x & 15; this.pos.y = y; this.pos.z = z & 15
40
88
  return col.getBlockStateId(this.pos)
41
89
  }
42
90
 
43
91
  info (stateId) {
44
- let i = this.cache.get(stateId)
45
- if (i) return i
46
- i = this._build(stateId)
47
- this.cache.set(stateId, i)
92
+ let i = this.infos[stateId]
93
+ if (i == null) i = this.infos[stateId] = this._build(stateId)
48
94
  return i
49
95
  }
50
96
 
@@ -118,33 +164,49 @@ class WorldView {
118
164
 
119
165
  // Collect every collision box that could touch `bb` (BlockCollisions semantics:
120
166
  // unloaded chunks collide with nothing, outside build height is air).
121
- collisionBoxes (bb, out = []) {
167
+ // The returned list and its boxes are reused by the next call.
168
+ collisionBoxes (bb) {
169
+ this.boxes.length = 0
170
+ this.scan(bb, false)
171
+ return this.boxes
172
+ }
173
+
174
+ noCollision (bb) {
175
+ return !this.scan(bb, true)
176
+ }
177
+
178
+ // walks the blocks around bb; with test set, stops at the first box that overlaps bb
179
+ scan (bb, test) {
180
+ const pool = this.boxPool
181
+ const out = this.boxes
122
182
  const x0 = Math.floor(bb.minX - 1.0e-7) - 1; const x1 = Math.floor(bb.maxX + 1.0e-7) + 1
123
183
  const y0 = Math.floor(bb.minY - 1.0e-7) - 1; const y1 = Math.floor(bb.maxY + 1.0e-7) + 1
124
184
  const z0 = Math.floor(bb.minZ - 1.0e-7) - 1; const z1 = Math.floor(bb.maxZ + 1.0e-7) + 1
125
185
  for (let x = x0; x <= x1; x++) {
126
186
  for (let z = z0; z <= z1; z++) {
127
- const col = this.bot.world.getColumn(x >> 4, z >> 4)
187
+ const col = this.column(x >> 4, z >> 4)
128
188
  if (!col) continue
189
+ const bottom = this.ticking ? this.bottom : this.minY
190
+ const top = this.ticking ? this.top : this.maxY
129
191
  for (let y = y0; y <= y1; y++) {
130
- if (y < this.minY || y >= this.maxY) continue
192
+ if (y < bottom || y >= top) continue
131
193
  this.pos.x = x & 15; this.pos.y = y; this.pos.z = z & 15
132
194
  const info = this.info(col.getBlockStateId(this.pos))
133
- const shapes = info.shapes
195
+ const shapes = info.isPowderSnow ? this.powderSnowShapes(y) : info.shapes
134
196
  for (let k = 0; k < shapes.length; k++) {
135
197
  const s = shapes[k]
136
- out.push([s[0] + x, s[1] + y, s[2] + z, s[3] + x, s[4] + y, s[5] + z])
198
+ if (test) {
199
+ if (bb.intersects(s[0] + x, s[1] + y, s[2] + z, s[3] + x, s[4] + y, s[5] + z)) return true
200
+ continue
201
+ }
202
+ const b = pool[out.length] ?? (pool[out.length] = new Array(6))
203
+ b[0] = s[0] + x; b[1] = s[1] + y; b[2] = s[2] + z; b[3] = s[3] + x; b[4] = s[4] + y; b[5] = s[5] + z
204
+ out.push(b)
137
205
  }
138
206
  }
139
207
  }
140
208
  }
141
- return out
142
- }
143
-
144
- noCollision (bb) {
145
- const boxes = this.collisionBoxes(bb)
146
- for (const b of boxes) if (bb.intersectsBox(b)) return false
147
- return true
209
+ return false
148
210
  }
149
211
 
150
212
  containsAnyLiquid (bb) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spectra-physics",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Vanilla-accurate client physics and movement for mineflayer (1.16.5 - 26.1)",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -37,6 +37,7 @@
37
37
  "node": ">=22"
38
38
  },
39
39
  "dependencies": {
40
+ "minecraft-data": "^3.117.0",
40
41
  "prismarine-block": "^1.23.0",
41
42
  "prismarine-chunk": "^1.39.0",
42
43
  "vec3": "^0.1.10"