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

     1  package entity
     2  
     3  import (
     4  	"github.com/df-mc/dragonfly/server/block"
     5  	"github.com/df-mc/dragonfly/server/block/cube"
     6  	"github.com/df-mc/dragonfly/server/world"
     7  	"github.com/go-gl/mathgl/mgl64"
     8  	"sync"
     9  	"time"
    10  )
    11  
    12  // Behaviour implements the behaviour of an Ent.
    13  type Behaviour interface {
    14  	// Tick ticks the Ent using the Behaviour. A Movement is returned that
    15  	// specifies the movement of the entity over the tick. Nil may be returned
    16  	// if the entity did not move.
    17  	Tick(e *Ent) *Movement
    18  }
    19  
    20  // Config allows specifying options that influence the way an Ent behaves.
    21  type Config struct {
    22  	Behaviour Behaviour
    23  }
    24  
    25  // New creates a new Ent using conf. The entity has a type and a position.
    26  func (conf Config) New(t world.EntityType, pos mgl64.Vec3) *Ent {
    27  	return &Ent{t: t, pos: pos, conf: conf}
    28  }
    29  
    30  // Ent is a world.Entity implementation that allows entity implementations to
    31  // share a lot of code. It is currently under development and is prone to
    32  // (breaking) changes.
    33  type Ent struct {
    34  	conf Config
    35  	t    world.EntityType
    36  
    37  	mu  sync.Mutex
    38  	pos mgl64.Vec3
    39  	vel mgl64.Vec3
    40  	rot cube.Rotation
    41  
    42  	name string
    43  
    44  	fireDuration time.Duration
    45  	age          time.Duration
    46  }
    47  
    48  // Explode propagates the explosion behaviour of the underlying Behaviour.
    49  func (e *Ent) Explode(src mgl64.Vec3, impact float64, conf block.ExplosionConfig) {
    50  	if expl, ok := e.conf.Behaviour.(interface {
    51  		Explode(e *Ent, src mgl64.Vec3, impact float64, conf block.ExplosionConfig)
    52  	}); ok {
    53  		expl.Explode(e, src, impact, conf)
    54  	}
    55  }
    56  
    57  // Type returns the world.EntityType passed to Config.New.
    58  func (e *Ent) Type() world.EntityType {
    59  	return e.t
    60  }
    61  
    62  func (e *Ent) Behaviour() Behaviour {
    63  	return e.conf.Behaviour
    64  }
    65  
    66  // Position returns the current position of the entity.
    67  func (e *Ent) Position() mgl64.Vec3 {
    68  	e.mu.Lock()
    69  	defer e.mu.Unlock()
    70  	return e.pos
    71  }
    72  
    73  // Velocity returns the current velocity of the entity. The values in the Vec3 returned represent the speed on
    74  // that axis in blocks/tick.
    75  func (e *Ent) Velocity() mgl64.Vec3 {
    76  	e.mu.Lock()
    77  	defer e.mu.Unlock()
    78  	return e.vel
    79  }
    80  
    81  // SetVelocity sets the velocity of the entity. The values in the Vec3 passed represent the speed on
    82  // that axis in blocks/tick.
    83  func (e *Ent) SetVelocity(v mgl64.Vec3) {
    84  	e.mu.Lock()
    85  	defer e.mu.Unlock()
    86  	e.vel = v
    87  }
    88  
    89  // Rotation returns the rotation of the entity.
    90  func (e *Ent) Rotation() cube.Rotation {
    91  	e.mu.Lock()
    92  	defer e.mu.Unlock()
    93  	return e.rot
    94  }
    95  
    96  // World returns the world of the entity.
    97  func (e *Ent) World() *world.World {
    98  	w, _ := world.OfEntity(e)
    99  	return w
   100  }
   101  
   102  // Age returns the total time lived of this entity. It increases by
   103  // time.Second/20 for every time Tick is called.
   104  func (e *Ent) Age() time.Duration {
   105  	e.mu.Lock()
   106  	defer e.mu.Unlock()
   107  	return e.age
   108  }
   109  
   110  // OnFireDuration ...
   111  func (e *Ent) OnFireDuration() time.Duration {
   112  	e.mu.Lock()
   113  	defer e.mu.Unlock()
   114  	return e.fireDuration
   115  }
   116  
   117  // SetOnFire ...
   118  func (e *Ent) SetOnFire(duration time.Duration) {
   119  	if duration < 0 {
   120  		duration = 0
   121  	}
   122  	e.mu.Lock()
   123  	before, after := e.fireDuration > 0, duration > 0
   124  	e.fireDuration = duration
   125  	pos := e.pos
   126  	e.mu.Unlock()
   127  
   128  	if before == after {
   129  		return
   130  	}
   131  	for _, v := range e.World().Viewers(pos) {
   132  		v.ViewEntityState(e)
   133  	}
   134  }
   135  
   136  // Extinguish ...
   137  func (e *Ent) Extinguish() {
   138  	e.SetOnFire(0)
   139  }
   140  
   141  // NameTag returns the name tag of the entity. An empty string is returned if
   142  // no name tag was set.
   143  func (e *Ent) NameTag() string {
   144  	e.mu.Lock()
   145  	defer e.mu.Unlock()
   146  	return e.name
   147  }
   148  
   149  // SetNameTag changes the name tag of an entity. The name tag is removed if an
   150  // empty string is passed.
   151  func (e *Ent) SetNameTag(s string) {
   152  	e.mu.Lock()
   153  	e.name = s
   154  	e.mu.Unlock()
   155  
   156  	for _, v := range e.World().Viewers(e.Position()) {
   157  		v.ViewEntityState(e)
   158  	}
   159  }
   160  
   161  // Tick ticks Ent, progressing its lifetime and closing the entity if it is
   162  // in the void.
   163  func (e *Ent) Tick(w *world.World, current int64) {
   164  	e.mu.Lock()
   165  	y := e.pos[1]
   166  	e.mu.Unlock()
   167  	if y < float64(w.Range()[0]) && current%10 == 0 {
   168  		_ = e.Close()
   169  		return
   170  	}
   171  	e.SetOnFire(e.OnFireDuration() - time.Second/20)
   172  
   173  	if m := e.conf.Behaviour.Tick(e); m != nil {
   174  		m.Send()
   175  	}
   176  	e.mu.Lock()
   177  	e.age += time.Second / 20
   178  	e.mu.Unlock()
   179  }
   180  
   181  // Close closes the Ent and removes the associated entity from the world.
   182  func (e *Ent) Close() error {
   183  	e.World().RemoveEntity(e)
   184  	return nil
   185  }