spectra-physics 1.0.0 → 1.1.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,203 @@
1
+ 'use strict'
2
+
3
+ const { f32, sin, cos, degToRadF, clamp } = require('../mth')
4
+ const { moveRelative } = require('./input')
5
+ const { move } = require('./move')
6
+ const { fluidFallingAdjusted } = require('./fluids')
7
+ const blocks = require('./blocks')
8
+
9
+ const F_098 = f32(0.98)
10
+ const F_091 = f32(0.91)
11
+ const F_08 = f32(0.8)
12
+ const F_09 = f32(0.9)
13
+ const F_096 = f32(0.96)
14
+ const F_002 = f32(0.02)
15
+ const F_0026 = f32(0.025999999)
16
+ const F_0216 = f32(0.21600002)
17
+ const F_0546 = f32(0.54600006)
18
+ const F_015 = f32(0.15)
19
+ const F_042 = f32(0.42)
20
+ const F_01 = f32(0.1)
21
+ const F_02 = f32(0.2)
22
+ const F_004 = f32(0.04)
23
+ const F_06 = 0.6000000238418579
24
+ const F_03 = 0.30000001192092896
25
+
26
+ function flyingSpeed (player) {
27
+ if (!player.V.flyingSpeedLive) return player.legacyFlyingSpeed
28
+ if (player.abilities.flying) return player.sprinting ? f32(player.abilities.flyingSpeed * 2) : player.abilities.flyingSpeed
29
+ return player.sprinting ? F_0026 : F_002
30
+ }
31
+
32
+ function frictionInfluencedSpeed (player, friction) {
33
+ if (player.onGround) return f32(player.movementSpeed() * f32(F_0216 / f32(f32(friction * friction) * friction)))
34
+ return flyingSpeed(player)
35
+ }
36
+
37
+ function handleOnClimbable (player) {
38
+ if (!blocks.onClimbable(player)) return
39
+ player.fallDistance = 0
40
+ player.vel.x = clamp(player.vel.x, -F_015, F_015)
41
+ player.vel.z = clamp(player.vel.z, -F_015, F_015)
42
+ let vy = Math.max(player.vel.y, -F_015)
43
+ if (vy < 0 && !blocks.feetBlock(player).isScaffolding && player.input.shift) vy = 0
44
+ player.vel.y = vy
45
+ }
46
+
47
+ function isFree (player, dx, dy, dz) {
48
+ const box = player.bb().move(dx, dy, dz)
49
+ return player.world.noCollision(box) && !player.world.containsAnyLiquid(box)
50
+ }
51
+
52
+ // LivingEntity#jumpFromGround
53
+ function jumpFromGround (player) {
54
+ const V = player.V
55
+ const strength = V.attributes2005 ? f32(player.env.attribute('jump_strength', 0.42)) : F_042
56
+ let power = f32(strength * blocks.jumpFactor(player))
57
+ const boost = player.env.effect('jump_boost')
58
+ if (boost != null) power = f32(power + f32(F_01 * (boost + 1)))
59
+ if (V.attributes2005 && power <= 1.0e-5) return
60
+ player.vel.y = V.jumpKeepsHigherY ? Math.max(power, player.vel.y) : power
61
+ if (!player.sprinting) return
62
+ const r = degToRadF(player.yRot)
63
+ if (V.jumpDoubleSprintBoost) {
64
+ player.vel.x += -sin(r) * 0.2
65
+ player.vel.z += cos(r) * 0.2
66
+ } else {
67
+ player.vel.x += f32(-sin(r) * F_02)
68
+ player.vel.z += f32(cos(r) * F_02)
69
+ }
70
+ }
71
+
72
+ // jump handling in LivingEntity#aiStep
73
+ function handleJump (player) {
74
+ if (!player.input.jumping || player.abilities.flying) {
75
+ player.noJumpDelay = 0
76
+ return
77
+ }
78
+ const inLava = player.isInLava()
79
+ const height = inLava ? player.fluidHeight.lava : player.fluidHeight.water
80
+ const inWater = player.isInWater() && height > 0
81
+ const threshold = player.eyeHeight() < 0.4 ? 0 : 0.4
82
+ if (inWater && !(player.onGround && !(height > threshold))) {
83
+ player.vel.y += F_004
84
+ } else if (inLava && !(player.onGround && !(height > threshold))) {
85
+ player.vel.y += F_004
86
+ } else if ((player.onGround || (inWater && height <= threshold)) && player.noJumpDelay === 0) {
87
+ jumpFromGround(player)
88
+ player.noJumpDelay = 10
89
+ }
90
+ }
91
+
92
+ function travelInWater (player, ix, iy, iz, gravity, falling) {
93
+ const V = player.V
94
+ const startY = player.pos.y
95
+ let friction = player.sprinting ? F_09 : F_08
96
+ let speed = F_002
97
+ let strider = V.efficiencyAttributes
98
+ ? f32(player.env.attribute('water_movement_efficiency', 0))
99
+ : Math.min(3, player.env.bootsEnchant('depth_strider'))
100
+ if (!player.onGround) strider = f32(strider * 0.5)
101
+ if (strider > 0) {
102
+ const divisor = V.efficiencyAttributes ? 1 : 3
103
+ friction = f32(friction + f32(f32(f32(F_0546 - friction) * strider) / divisor))
104
+ speed = f32(speed + f32(f32(f32(player.movementSpeed() - speed) * strider) / divisor))
105
+ }
106
+ if (player.env.effect('dolphins_grace') != null) friction = F_096
107
+ moveRelative(player, speed, ix, iy, iz)
108
+ move(player, player.vel.x, player.vel.y, player.vel.z)
109
+ if (player.horizontalCollision && blocks.onClimbable(player)) player.vel.y = 0.2
110
+ player.vel.x *= friction
111
+ player.vel.y *= F_08
112
+ player.vel.z *= friction
113
+ fluidFallingAdjusted(player, gravity, falling)
114
+ if (player.horizontalCollision && isFree(player, player.vel.x, player.vel.y + F_06 - player.pos.y + startY, player.vel.z)) {
115
+ player.vel.y = F_03
116
+ }
117
+ }
118
+
119
+ function travelInLava (player, ix, iy, iz, gravity, falling) {
120
+ const startY = player.pos.y
121
+ moveRelative(player, F_002, ix, iy, iz)
122
+ move(player, player.vel.x, player.vel.y, player.vel.z)
123
+ if (player.fluidHeight.lava <= 0.4) {
124
+ player.vel.x *= 0.5
125
+ player.vel.y *= F_08
126
+ player.vel.z *= 0.5
127
+ fluidFallingAdjusted(player, gravity, falling)
128
+ } else {
129
+ player.vel.x *= 0.5
130
+ player.vel.y *= 0.5
131
+ player.vel.z *= 0.5
132
+ }
133
+ player.vel.y += -gravity / 4
134
+ if (player.horizontalCollision && isFree(player, player.vel.x, player.vel.y + F_06 - player.pos.y + startY, player.vel.z)) {
135
+ player.vel.y = F_03
136
+ }
137
+ }
138
+
139
+ function travelInAir (player, ix, iy, iz, gravity) {
140
+ const below = blocks.belowPos(player)
141
+ const friction = player.world.blockAt(below.x, below.y, below.z).friction
142
+ const drag = player.onGround ? f32(friction * F_091) : F_091
143
+ moveRelative(player, frictionInfluencedSpeed(player, friction), ix, iy, iz)
144
+ handleOnClimbable(player)
145
+ move(player, player.vel.x, player.vel.y, player.vel.z)
146
+ if ((player.horizontalCollision || player.input.jumping) && (blocks.onClimbable(player) || blocks.onPowderSnowWithBoots(player))) {
147
+ player.vel.y = 0.2
148
+ }
149
+ let vy = player.vel.y
150
+ const levitation = player.env.effect('levitation')
151
+ if (levitation != null) {
152
+ vy += (0.05 * (levitation + 1) - player.vel.y) * 0.2
153
+ player.fallDistance = 0
154
+ } else if (!player.world.hasChunk(below.x, below.z)) {
155
+ vy = player.pos.y > player.world.minY ? -0.1 : 0
156
+ } else {
157
+ vy -= gravity
158
+ }
159
+ player.vel.x *= drag
160
+ player.vel.y = vy * F_098
161
+ player.vel.z *= drag
162
+ }
163
+
164
+ // LivingEntity#travel
165
+ function livingTravel (player, ix, iy, iz) {
166
+ const falling = player.vel.y <= 0
167
+ let gravity = player.V.attributes2005 ? player.env.attribute('gravity', 0.08) : 0.08
168
+ if (falling && player.env.effect('slow_falling') != null) {
169
+ gravity = player.V.attributes2005 ? Math.min(gravity, 0.01) : 0.01
170
+ player.fallDistance = 0
171
+ }
172
+ const affected = !player.abilities.flying
173
+ if (player.isInWater() && affected) travelInWater(player, ix, iy, iz, gravity, falling)
174
+ else if (player.isInLava() && affected) travelInLava(player, ix, iy, iz, gravity, falling)
175
+ else travelInAir(player, ix, iy, iz, gravity)
176
+ }
177
+
178
+ function swimTowardsLook (player) {
179
+ const lookY = -sin(degToRadF(player.xRot))
180
+ const k = lookY < -0.2 ? 0.085 : 0.06
181
+ const above = player.world.fluidAt(Math.floor(player.pos.x), Math.floor(player.pos.y + 1 - 0.1), Math.floor(player.pos.z))
182
+ if (lookY <= 0 || player.input.jumping || above) player.vel.y += (lookY - player.vel.y) * k
183
+ }
184
+
185
+ // Player#travel
186
+ function travel (player) {
187
+ const ix = player.xxa
188
+ const iz = player.zza
189
+ if (player.swimming && !player.riding) swimTowardsLook(player)
190
+ if (!player.abilities.flying) {
191
+ livingTravel(player, ix, 0, iz)
192
+ return
193
+ }
194
+ const startVy = player.vel.y
195
+ const saved = player.legacyFlyingSpeed
196
+ if (!player.V.flyingSpeedLive) player.legacyFlyingSpeed = f32(player.abilities.flyingSpeed * (player.sprinting ? 2 : 1))
197
+ livingTravel(player, ix, 0, iz)
198
+ player.vel.y = startVy * 0.6
199
+ player.legacyFlyingSpeed = saved
200
+ player.fallDistance = 0
201
+ }
202
+
203
+ module.exports = { travel, handleJump }
@@ -1,14 +1,14 @@
1
1
  'use strict'
2
- // Version switches for client behaviour that differs between 1.16.5 and 26.x.
3
- // Uses the protocol version number so "1.21.3" (768) == "1.21.2" etc.
2
+ // Client behaviour that changed between 1.16.5 and 26.x, keyed by protocol number
3
+ // ("1.21.3" is 768, the same as 1.21.2).
4
4
 
5
5
  const PV = {
6
6
  '1.16.5': 754,
7
7
  '1.17': 755,
8
+ '1.18.2': 758,
8
9
  '1.19.4': 762,
9
10
  '1.20': 763,
10
11
  '1.20.2': 764,
11
- '1.20.3': 765,
12
12
  '1.20.5': 766,
13
13
  '1.21': 767,
14
14
  '1.21.2': 768,
@@ -19,34 +19,57 @@ const PV = {
19
19
  }
20
20
 
21
21
  function versionFlags (registry) {
22
- const pv = registry.version['>='] ? registry.version.version : registry.version
22
+ const pv = registry.version.version
23
23
  const at = (name) => pv >= PV[name]
24
24
  return {
25
25
  protocol: pv,
26
26
  name: registry.version.minecraftVersion,
27
- // login / configuration
28
- configPhase: at('1.20.2'), // brand + client information are sent in the configuration phase
29
- // movement packets
30
- movementFlags: at('1.21.2'), // onGround + horizontalCollision bitflags in move packets
31
- tickEnd: at('1.21.2'), // ServerboundClientTickEndPacket after every client tick
32
- playerInputPacket: at('1.21.2'), // ServerboundPlayerInputPacket sent on key change (replaces steer_vehicle)
33
- shiftInInput: at('1.21.6'), // no more PRESS/RELEASE_SHIFT_KEY player commands
34
- clientLoaded: at('1.21.4'), // player does not tick until the level screen closes, then sends player_loaded
35
- posRotBeforeConfirm: pv === PV['1.21.2'], // 1.21.2/1.21.3 answer teleports with pos-rot *before* accept-teleportation
36
- relativeTeleportVelocity: at('1.21.2'), // teleport packet carries delta movement + delta flags
37
- lpVelocity: at('1.21.9'), // entity_velocity uses lpVec3 (already blocks/tick)
38
- // physics
39
- posFromBoundingBox: !at('1.17'), // 1.16 recalculates the position from the bounding box centre
40
- flyingSpeedLive: at('1.19.4'), // Player#getFlyingSpeed() instead of the lagging flyingSpeed field
41
- minorCollision: at('1.19.4'), // sprinting survives "minor" horizontal collisions
42
- supportingBlock: at('1.20'), // mainSupportingBlockPos drives the block below
43
- attributes2005: at('1.20.5'), // gravity / step_height / jump_strength attributes
44
- jumpKeepsHigherY: at('1.21'),
45
- modernStepUp: at('1.21'), // collectCandidateStepUpHeights step algorithm
46
- normalizedInput: at('1.21.2'), // KeyboardInput#moveVector is normalized
47
- modernBackOff: at('1.21.2'), // canFallAtLeast based sneak edge back-off
48
- squareInput: at('1.21.5'), // modifyInputSpeedForSquareMovement
27
+
28
+ // connection
29
+ configPhase: at('1.20.2'),
30
+ movementFlags: at('1.21.2'),
31
+ tickEnd: at('1.21.2'),
32
+ playerInputPacket: at('1.21.2'),
33
+ shiftInInput: at('1.21.6'),
34
+ clientLoaded: at('1.21.4'),
35
+ posRotBeforeConfirm: pv === PV['1.21.2'],
36
+ relativeTeleportVelocity: at('1.21.2'),
37
+ lpVelocity: at('1.21.9'),
38
+ pointThree: !at('1.18.2'), // position is only reported after moving 0.03 (later 0.0002)
39
+
40
+ // input
41
+ inputModel: at('1.21.5') ? 'modern' : 'legacy',
42
+ floatSqrt: !at('1.17'),
43
+ normalizeEpsilon: at('1.21.2') ? Math.fround(1.0e-5) : 1.0e-4,
44
+ horizontalThreshold: at('1.21.5'), // tiny horizontal speed is cut by length, not per axis
45
+
46
+ // movement
47
+ posFromBoundingBox: !at('1.17'),
48
+ epsilonCollisionFlags: at('1.18.2'),
49
+ keepsXOnCornerCollision: !at('1.18.2'), // 1.14 - 1.18.1 bug
50
+ modernMoveThreshold: at('1.21.2'),
51
+ modernStepUp: at('1.21'),
52
+ supportingBlock: at('1.20'),
53
+ minorCollision: at('1.19.4'),
49
54
  fallDistanceDouble: at('1.21.5'),
55
+
56
+ // speed
57
+ flyingSpeedLive: at('1.19.4'),
58
+ airSprintFloatSum: at('1.18.2'),
59
+ attributes2005: at('1.20.5'),
60
+ efficiencyAttributes: at('1.21'), // movement_efficiency / water_movement_efficiency
61
+ soulSpeedBoots: pv >= 751 && !at('1.21'),
62
+ jumpDoubleSprintBoost: at('1.20.5'),
63
+ jumpKeepsHigherY: at('1.21.2'),
64
+
65
+ // world interaction
66
+ blockEffectsAfterTravel: at('1.21.2'),
67
+ blockEffectsPerAxis: at('1.21.5'),
68
+ insideBlockDeflate: at('1.19.4') ? 1.0e-5 : 0.001,
69
+ fluidRecheckInMove: pv !== PV['1.21.4'],
70
+ swimmingNeedsFeetInWater: at('1.17'),
71
+ powderSnow: at('1.17'),
72
+
50
73
  // vehicles
51
74
  moveVehicleOnGround: at('1.21.2')
52
75
  }
@@ -79,9 +79,12 @@ class WorldView {
79
79
  isPowderSnow: name === 'powder_snow',
80
80
  isScaffolding: name === 'scaffolding',
81
81
  isFenceLike: name.endsWith('_fence') || name.endsWith('_wall') || name.endsWith('_fence_gate'),
82
+ isBubbleColumn: name === 'bubble_column',
83
+ bubbleDrag: props.drag === true || props.drag === 'true',
82
84
  fullCube: shapes.length === 1 && shapes[0].every((v, k) => v === FULL[k]),
83
85
  fluid: null
84
86
  }
87
+ info.suffocating = info.fullCube && !(b?.transparent ?? true)
85
88
  // fluids
86
89
  if (name === 'water' || name === 'lava' || name === 'flowing_water' || name === 'flowing_lava') {
87
90
  const level = Number(props.level ?? 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spectra-physics",
3
- "version": "1.0.0",
3
+ "version": "1.1.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": [