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 }