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 }