github.com/df-mc/dragonfly@v0.9.13/server/entity/passive.go (about)

     1  package entity
     2  
     3  import (
     4  	"github.com/df-mc/dragonfly/server/block"
     5  	"github.com/go-gl/mathgl/mgl64"
     6  	"math"
     7  	"time"
     8  )
     9  
    10  // PassiveBehaviourConfig holds optional parameters for a PassiveBehaviour.
    11  type PassiveBehaviourConfig struct {
    12  	// Gravity is the amount of Y velocity subtracted every tick.
    13  	Gravity float64
    14  	// Drag is used to reduce all axes of the velocity every tick. Velocity is
    15  	// multiplied with (1-Drag) every tick.
    16  	Drag float64
    17  	// ExistenceDuration is the duration that an entity with this behaviour
    18  	// should last. Once this time expires, the entity is closed. If
    19  	// ExistenceDuration is 0, the entity will never expire automatically.
    20  	ExistenceDuration time.Duration
    21  	// Expire is called when the entity expires due to its age reaching the
    22  	// ExistenceDuration.
    23  	Expire func(e *Ent)
    24  	// Tick is called for every tick that the entity is alive. Tick is called
    25  	// after the entity moves on a tick.
    26  	Tick func(e *Ent)
    27  }
    28  
    29  // New creates a PassiveBehaviour using the parameters in conf.
    30  func (conf PassiveBehaviourConfig) New() *PassiveBehaviour {
    31  	if conf.ExistenceDuration == 0 {
    32  		conf.ExistenceDuration = math.MaxInt64
    33  	}
    34  	return &PassiveBehaviour{conf: conf, fuse: conf.ExistenceDuration, mc: &MovementComputer{
    35  		Gravity:           conf.Gravity,
    36  		Drag:              conf.Drag,
    37  		DragBeforeGravity: true,
    38  	}}
    39  }
    40  
    41  // PassiveBehaviour implements Behaviour for entities that act passively. This
    42  // means that they can move, but only under influence of the environment, which
    43  // includes, for example, falling, and flowing water.
    44  type PassiveBehaviour struct {
    45  	conf PassiveBehaviourConfig
    46  	mc   *MovementComputer
    47  
    48  	close        bool
    49  	fallDistance float64
    50  	fuse         time.Duration
    51  }
    52  
    53  // Explode adds velocity to a passive entity to blast it away from the
    54  // explosion's source.
    55  func (p *PassiveBehaviour) Explode(e *Ent, src mgl64.Vec3, impact float64, _ block.ExplosionConfig) {
    56  	e.vel = e.vel.Add(e.pos.Sub(src).Normalize().Mul(impact))
    57  }
    58  
    59  // Fuse returns the leftover time until PassiveBehaviourConfig.Expire is called,
    60  // or -1 if this function is not set.
    61  func (p *PassiveBehaviour) Fuse() time.Duration {
    62  	if p.conf.Expire != nil {
    63  		return p.fuse
    64  	}
    65  	return -1
    66  }
    67  
    68  // Tick implements the behaviour for a passive entity. It performs movement and
    69  // updates its state.
    70  func (p *PassiveBehaviour) Tick(e *Ent) *Movement {
    71  	if p.close {
    72  		_ = e.Close()
    73  		return nil
    74  	}
    75  	e.mu.Lock()
    76  
    77  	m := p.mc.TickMovement(e, e.pos, e.vel, e.rot)
    78  	e.pos, e.vel = m.pos, m.vel
    79  
    80  	p.fallDistance = math.Max(p.fallDistance-m.dvel[1], 0)
    81  	e.mu.Unlock()
    82  
    83  	p.fuse = p.conf.ExistenceDuration - e.Age()
    84  
    85  	if p.conf.Tick != nil {
    86  		p.conf.Tick(e)
    87  	}
    88  
    89  	w := e.World()
    90  	if p.Fuse()%(time.Second/4) == 0 {
    91  		for _, v := range w.Viewers(m.pos) {
    92  			v.ViewEntityState(e)
    93  		}
    94  	}
    95  
    96  	if e.Age() > p.conf.ExistenceDuration {
    97  		p.close = true
    98  		if p.conf.Expire != nil {
    99  			p.conf.Expire(e)
   100  		}
   101  	}
   102  	return m
   103  }