diff --git a/server/block/explosion.go b/server/block/explosion.go index 1c57e7edf..a6a31f361 100644 --- a/server/block/explosion.go +++ b/server/block/explosion.go @@ -111,7 +111,7 @@ func (c ExplosionConfig) Explode(tx *world.Tx, src world.ExplosionSource) { for e := range tx.EntitiesWithin(box.Grow(2)) { pos := e.Position() dist := pos.Sub(explosionPos).Len() - if dist > d || dist == 0 { + if dist > d { continue } diff --git a/server/entity/direction.go b/server/entity/direction.go index 770cb06e0..64cc3e748 100644 --- a/server/entity/direction.go +++ b/server/entity/direction.go @@ -20,3 +20,12 @@ func EyePosition(e world.Entity) mgl64.Vec3 { } return pos } + +// ExplosionImpulse returns the velocity added to an entity by an explosion. +func ExplosionImpulse(e world.Entity, src world.ExplosionSource, impact float64) mgl64.Vec3 { + direction := EyePosition(e).Sub(src.Position()) + if direction.Len() == 0 { + return mgl64.Vec3{} + } + return direction.Normalize().Mul(impact) +} diff --git a/server/entity/passive.go b/server/entity/passive.go index 6e447cd74..b7be89022 100644 --- a/server/entity/passive.go +++ b/server/entity/passive.go @@ -64,7 +64,7 @@ type PassiveBehaviour struct { // Explode adds velocity to a passive entity to blast it away from the // explosion's source. func (p *PassiveBehaviour) Explode(e *Ent, src world.ExplosionSource, impact float64) { - e.data.Vel = e.data.Vel.Add(e.data.Pos.Sub(src.Position()).Normalize().Mul(impact)) + e.data.Vel = e.data.Vel.Add(ExplosionImpulse(e, src, impact)) } // Fuse returns the leftover time until PassiveBehaviourConfig.Expire is called, diff --git a/server/entity/projectile.go b/server/entity/projectile.go index 1d9be719b..14c28a3fb 100644 --- a/server/entity/projectile.go +++ b/server/entity/projectile.go @@ -136,7 +136,7 @@ func (lt *ProjectileBehaviour) Owner() *world.EntityHandle { // Explode adds velocity to a projectile to blast it away from the explosion's // source. func (lt *ProjectileBehaviour) Explode(e *Ent, src world.ExplosionSource, impact float64) { - e.data.Vel = e.Velocity().Add(e.Position().Sub(src.Position()).Normalize().Mul(impact)) + e.data.Vel = e.Velocity().Add(ExplosionImpulse(e, src, impact)) } // Potion returns the potion.Potion that is applied to an entity if hit by the diff --git a/server/player/player.go b/server/player/player.go index 2049a0834..d19019770 100644 --- a/server/player/player.go +++ b/server/player/player.go @@ -715,10 +715,14 @@ func (p *Player) FinalDamageFrom(dmg float64, src world.DamageSource) float64 { // Explode ... func (p *Player) Explode(src world.ExplosionSource, impact float64) { - explosionPos := src.Position() - diff := p.Position().Sub(explosionPos) + // Java uses Blast Protection's explosion-specific resistance here, not innate armour knockback resistance. + resistance := min(float64(p.Armour().HighestEnchantmentLevel(enchantment.BlastProtection))*0.15, 1) p.Hurt(math.Floor((impact*impact+impact)*3.5*src.Size()*2+1), entity.ExplosionDamageSource{Source: src}) - p.knockBack(explosionPos, impact, diff[1]/diff.Len()*impact) + + impulse := entity.ExplosionImpulse(p, src, impact*(1-resistance)) + velocity := p.Velocity().Add(impulse) + p.data.Vel = velocity + p.SetVelocity(velocity) } // SetAbsorption sets the absorption health of a player. This extra health shows as golden hearts and do not