Skip to content

Commit

Permalink
player/player.go: Attempt at fixing and cleaning up attack immunity.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sandertv committed Nov 27, 2024
1 parent 32b8200 commit 9a8b082
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 56 deletions.
3 changes: 0 additions & 3 deletions server/block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,6 @@ func newFlammabilityInfo(encouragement, flammability int, lavaFlammable bool) Fl

// livingEntity ...
type livingEntity interface {
// AttackImmune checks if the entity is currently immune to entity attacks. Entities typically turn
// immune for half a second after being attacked.
AttackImmune() bool
// Hurt hurts the entity for a given amount of damage. The source passed represents the cause of the
// damage, for example damage.SourceEntityAttack if the entity is attacked by another entity.
// If the final damage exceeds the health that the entity currently has, the entity is killed.
Expand Down
2 changes: 1 addition & 1 deletion server/block/cactus.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (c Cactus) canGrowHere(pos cube.Pos, tx *world.Tx, recursive bool) bool {

// EntityInside ...
func (c Cactus) EntityInside(_ cube.Pos, _ *world.Tx, e world.Entity) {
if l, ok := e.(livingEntity); ok && !l.AttackImmune() {
if l, ok := e.(livingEntity); ok {
l.Hurt(0.5, DamageSource{Block: c})
}
}
Expand Down
2 changes: 1 addition & 1 deletion server/block/campfire.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func (c Campfire) EntityInside(pos cube.Pos, tx *world.Tx, e world.Entity) {
tx.SetBlock(pos, c, nil)
}
if !c.Extinguished {
if l, ok := e.(livingEntity); ok && !l.AttackImmune() {
if l, ok := e.(livingEntity); ok {
l.Hurt(c.Type.Damage(), FireDamageSource{})
}
}
Expand Down
2 changes: 1 addition & 1 deletion server/block/fire.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ func (f Fire) spread(from, to cube.Pos, tx *world.Tx, r *rand.Rand) {
// EntityInside ...
func (f Fire) EntityInside(_ cube.Pos, _ *world.Tx, e world.Entity) {
if flammable, ok := e.(flammableEntity); ok {
if l, ok := e.(livingEntity); ok && !l.AttackImmune() {
if l, ok := e.(livingEntity); ok {
l.Hurt(f.Type.Damage(), FireDamageSource{})
}
if flammable.OnFireDuration() < time.Second*8 {
Expand Down
2 changes: 1 addition & 1 deletion server/block/lava.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (l Lava) EntityInside(_ cube.Pos, _ *world.Tx, e world.Entity) {
fallEntity.ResetFallDistance()
}
if flammable, ok := e.(flammableEntity); ok {
if l, ok := e.(livingEntity); ok && !l.AttackImmune() {
if l, ok := e.(livingEntity); ok {
l.Hurt(4, LavaDamageSource{})
}
flammable.SetOnFire(15 * time.Second)
Expand Down
3 changes: 0 additions & 3 deletions server/entity/living.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ type Living interface {
// Dead checks if the entity is considered dead. True is returned if the health of the entity is equal to or
// lower than 0.
Dead() bool
// AttackImmune checks if the entity is currently immune to entity attacks. Entities typically turn
// immune for half a second after being attacked.
AttackImmune() bool
// Hurt hurts the entity for a given amount of damage. The source passed represents the cause of the
// damage, for example AttackDamageSource if the entity is attacked by another entity.
// If the final damage exceeds the health that the entity currently has, the entity is killed.
Expand Down
1 change: 1 addition & 0 deletions server/player/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type Handler interface {
// HandleHurt handles the player being hurt by any damage source. ctx.Cancel() may be called to cancel the
// damage being dealt to the player.
// The damage dealt to the player may be changed by assigning to *damage.
// *damage is the final damage dealt to the player.
HandleHurt(ctx *Context, damage *float64, attackImmunity *time.Duration, src world.DamageSource)
// HandleDeath handles the player dying to a particular damage cause.
HandleDeath(p *Player, src world.DamageSource, keepInv *bool)
Expand Down
76 changes: 30 additions & 46 deletions server/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ type playerData struct {
experience *entity.ExperienceManager
effects *entity.EffectManager

lastXPPickup *time.Time
immunityTicks int64
lastXPPickup *time.Time

lastDamage float64
immuneUntil time.Time

deathPos *mgl64.Vec3
deathDimension world.Dimension
Expand Down Expand Up @@ -525,30 +527,27 @@ func (p *Player) fall(distance float64) {
// final damage dealt to the Player and if the Player was vulnerable to this
// kind of damage.
func (p *Player) Hurt(dmg float64, src world.DamageSource) (float64, bool) {
if _, ok := p.Effect(effect.FireResistance{}); (ok && src.Fire()) || p.Dead() || !p.GameMode().AllowsTakingDamage() {
if _, ok := p.Effect(effect.FireResistance{}); (ok && src.Fire()) || p.Dead() || !p.GameMode().AllowsTakingDamage() || dmg < 0 {
return 0, false
}
totalDamage := p.FinalDamageFrom(dmg, src)
damageLeft := totalDamage
if p.immuneUntil.Before(time.Now()) {
if damageLeft = damageLeft - p.lastDamage; damageLeft <= 0 {
return 0, false
}
}

immunity := time.Second / 2
ctx := event.C(p)
if p.Handler().HandleHurt(ctx, &dmg, &immunity, src); ctx.Cancelled() {
if p.Handler().HandleHurt(ctx, &damageLeft, &immunity, src); ctx.Cancelled() {
return 0, false
}
if dmg < 0 {
return 0, true
}

totalDamage := p.FinalDamageFrom(dmg, src)
damageLeft := totalDamage
p.setAttackImmunity(immunity, damageLeft)

if a := p.Absorption(); a > 0 {
if damageLeft > a {
p.SetAbsorption(0)
damageLeft -= a
} else {
p.SetAbsorption(a - damageLeft)

damageLeft = 0
}
p.SetAbsorption(a - damageLeft)
damageLeft = max(0, damageLeft-a)
}

if p.Health()-damageLeft <= mgl64.Epsilon {
Expand All @@ -569,15 +568,15 @@ func (p *Player) Hurt(dmg float64, src world.DamageSource) (float64, bool) {
if src.ReducedByArmour() {
p.Exhaust(0.1)
p.Armour().Damage(dmg, p.damageItem)

var origin world.Entity
if s, ok := src.(entity.AttackDamageSource); ok {
origin = s.Attacker
} else if s, ok := src.(entity.ProjectileDamageSource); ok {
origin = s.Owner
}
if l, ok := origin.(entity.Living); ok {
thornsDmg := p.Armour().ThornsDamage(p.damageItem)
if thornsDmg > 0 {
if thornsDmg := p.Armour().ThornsDamage(p.damageItem); thornsDmg > 0 {
l.Hurt(thornsDmg, enchantment.ThornsDamageSource{Owner: p})
}
}
Expand All @@ -593,7 +592,6 @@ func (p *Player) Hurt(dmg float64, src world.DamageSource) (float64, bool) {
p.tx.PlaySound(pos, sound.Drowning{})
}

p.SetAttackImmunity(immunity)
if p.Dead() {
p.kill(src)
}
Expand Down Expand Up @@ -624,7 +622,7 @@ func (p *Player) applyTotemEffects() {
// enchantments on the individual pieces.
// The damage returned will be at the least 0.
func (p *Player) FinalDamageFrom(dmg float64, src world.DamageSource) float64 {
dmg = math.Max(dmg, 0)
dmg = max(dmg, 0)

dmg -= p.Armour().DamageReduction(dmg, src)
if res, ok := p.Effect(effect.Resistance{}); ok {
Expand All @@ -644,7 +642,7 @@ func (p *Player) Explode(explosionPos mgl64.Vec3, impact float64, c block.Explos
// actually increase the maximum health. Once the hearts are lost, they will not regenerate.
// Nothing happens if a negative number is passed.
func (p *Player) SetAbsorption(health float64) {
p.absorptionHealth = math.Max(health, 0)
p.absorptionHealth = max(health, 0)
p.session().SendHealth(p.Health(), p.MaxHealth(), p.absorptionHealth)
}

Expand Down Expand Up @@ -677,19 +675,10 @@ func (p *Player) knockBack(src mgl64.Vec3, force, height float64) {
p.SetVelocity(velocity.Mul(1 - p.Armour().KnockBackResistance()))
}

// AttackImmune checks if the player is currently immune to entity attacks, meaning it was recently attacked.
func (p *Player) AttackImmune() bool {
return p.immunityTicks > 0
}

// AttackImmunity returns the duration the player is immune to entity attacks.
func (p *Player) AttackImmunity() time.Duration {
return time.Duration(p.immunityTicks) * time.Second / 20
}

// SetAttackImmunity sets the duration the player is immune to entity attacks.
func (p *Player) SetAttackImmunity(d time.Duration) {
p.immunityTicks = d.Milliseconds() / 50
// setAttackImmunity sets the duration the player is immune to entity attacks.
func (p *Player) setAttackImmunity(d time.Duration, dmg float64) {
p.immuneUntil = time.Now().Add(d)
p.lastDamage = dmg
}

// Food returns the current food level of a player. The level returned is guaranteed to always be between 0
Expand Down Expand Up @@ -1590,9 +1579,6 @@ func (p *Player) AttackEntity(e world.Entity) bool {
if !ok {
return false
}
if living.AttackImmune() {
return true
}

dmg := i.AttackDamage()
if strength, ok := p.Effect(effect.Strength{}); ok {
Expand Down Expand Up @@ -2029,7 +2015,7 @@ func (p *Player) Move(deltaPos mgl64.Vec3, deltaYaw, deltaPitch float64) {
p.fallDistance = 1.0
}
if p.collidedHorizontally {
if force := horizontalVel.Len()*10.0 - 3.0; force > 0.0 && !p.AttackImmune() {
if force := horizontalVel.Len()*10.0 - 3.0; force > 0.0 {
p.tx.PlaySound(p.Position(), sound.Fall{Distance: force})
p.Hurt(force, entity.GlideDamageSource{})
}
Expand Down Expand Up @@ -2301,11 +2287,11 @@ func (p *Player) Tick(_ *world.Tx, current int64) {

p.tickFood()
p.tickAirSupply()
p.immunityTicks = max(p.immunityTicks-1, 0)

if p.Position()[1] < float64(p.tx.Range()[0]) && p.GameMode().AllowsTakingDamage() && current%10 == 0 {
p.Hurt(4, entity.VoidDamageSource{})
}
if !p.AttackImmune() && p.insideOfSolid() {
if p.insideOfSolid() {
p.Hurt(1, entity.SuffocationDamageSource{})
}

Expand All @@ -2314,7 +2300,7 @@ func (p *Player) Tick(_ *world.Tx, current int64) {
if !p.GameMode().AllowsTakingDamage() || p.OnFireDuration() <= 0 || p.tx.RainingAt(cube.PosFromVec3(p.Position())) {
p.Extinguish()
}
if p.OnFireDuration()%time.Second == 0 && !p.AttackImmune() {
if p.OnFireDuration()%time.Second == 0 {
p.Hurt(1, block.FireDamageSource{})
}
}
Expand Down Expand Up @@ -2354,9 +2340,7 @@ func (p *Player) tickAirSupply() {
}
if p.airSupplyTicks -= 1; p.airSupplyTicks <= -20 {
p.airSupplyTicks = 0
if !p.AttackImmune() {
p.Hurt(2, entity.DrowningDamageSource{})
}
p.Hurt(2, entity.DrowningDamageSource{})
}
p.breathing = false
p.updateState()
Expand Down

0 comments on commit 9a8b082

Please sign in to comment.