142 lines
3.6 KiB
Go
142 lines
3.6 KiB
Go
|
|
package entity
|
||
|
|
|
||
|
|
import (
|
||
|
|
"github.com/df-mc/dragonfly/server/block"
|
||
|
|
"github.com/df-mc/dragonfly/server/block/cube"
|
||
|
|
"github.com/df-mc/dragonfly/server/world"
|
||
|
|
"github.com/go-gl/mathgl/mgl64"
|
||
|
|
"sync"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Behaviour implements the behaviour of an Ent.
|
||
|
|
type Behaviour interface {
|
||
|
|
// Tick ticks the Ent using the Behaviour. A Movement is returned that
|
||
|
|
// specifies the movement of the entity over the tick. Nil may be returned
|
||
|
|
// if the entity did not move.
|
||
|
|
Tick(e *Ent, tx *world.Tx) *Movement
|
||
|
|
}
|
||
|
|
|
||
|
|
// Ent is a world.Entity implementation that allows entity implementations to
|
||
|
|
// share a lot of code. It is currently under development and is prone to
|
||
|
|
// (breaking) changes.
|
||
|
|
type Ent struct {
|
||
|
|
tx *world.Tx
|
||
|
|
handle *world.EntityHandle
|
||
|
|
data *world.EntityData
|
||
|
|
once sync.Once
|
||
|
|
}
|
||
|
|
|
||
|
|
// Open converts a world.EntityHandle to an Ent in a world.Tx.
|
||
|
|
func Open(tx *world.Tx, handle *world.EntityHandle, data *world.EntityData) *Ent {
|
||
|
|
return &Ent{tx: tx, handle: handle, data: data}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (e *Ent) H() *world.EntityHandle {
|
||
|
|
return e.handle
|
||
|
|
}
|
||
|
|
|
||
|
|
func (e *Ent) Behaviour() Behaviour {
|
||
|
|
return e.data.Data.(Behaviour)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Explode propagates the explosion behaviour of the underlying Behaviour.
|
||
|
|
func (e *Ent) Explode(src mgl64.Vec3, impact float64, conf block.ExplosionConfig) {
|
||
|
|
if expl, ok := e.Behaviour().(interface {
|
||
|
|
Explode(e *Ent, src mgl64.Vec3, impact float64, conf block.ExplosionConfig)
|
||
|
|
}); ok {
|
||
|
|
expl.Explode(e, src, impact, conf)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Position returns the current position of the entity.
|
||
|
|
func (e *Ent) Position() mgl64.Vec3 {
|
||
|
|
return e.data.Pos
|
||
|
|
}
|
||
|
|
|
||
|
|
// Velocity returns the current velocity of the entity. The values in the Vec3 returned represent the speed on
|
||
|
|
// that axis in blocks/tick.
|
||
|
|
func (e *Ent) Velocity() mgl64.Vec3 {
|
||
|
|
return e.data.Vel
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetVelocity sets the velocity of the entity. The values in the Vec3 passed represent the speed on
|
||
|
|
// that axis in blocks/tick.
|
||
|
|
func (e *Ent) SetVelocity(v mgl64.Vec3) {
|
||
|
|
e.data.Vel = v
|
||
|
|
}
|
||
|
|
|
||
|
|
// Rotation returns the rotation of the entity.
|
||
|
|
func (e *Ent) Rotation() cube.Rotation {
|
||
|
|
return e.data.Rot
|
||
|
|
}
|
||
|
|
|
||
|
|
// Age returns the total time lived of this entity. It increases by
|
||
|
|
// time.Second/20 for every time Tick is called.
|
||
|
|
func (e *Ent) Age() time.Duration {
|
||
|
|
return e.data.Age
|
||
|
|
}
|
||
|
|
|
||
|
|
// OnFireDuration ...
|
||
|
|
func (e *Ent) OnFireDuration() time.Duration {
|
||
|
|
return e.data.FireDuration
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetOnFire ...
|
||
|
|
func (e *Ent) SetOnFire(duration time.Duration) {
|
||
|
|
duration = max(duration, 0)
|
||
|
|
stateChanged := (e.data.FireDuration > 0) != (duration > 0)
|
||
|
|
|
||
|
|
e.data.FireDuration = duration
|
||
|
|
if stateChanged {
|
||
|
|
for _, v := range e.tx.Viewers(e.data.Pos) {
|
||
|
|
v.ViewEntityState(e)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Extinguish ...
|
||
|
|
func (e *Ent) Extinguish() {
|
||
|
|
e.SetOnFire(0)
|
||
|
|
}
|
||
|
|
|
||
|
|
// NameTag returns the name tag of the entity. An empty string is returned if
|
||
|
|
// no name tag was set.
|
||
|
|
func (e *Ent) NameTag() string {
|
||
|
|
return e.data.Name
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetNameTag changes the name tag of an entity. The name tag is removed if an
|
||
|
|
// empty string is passed.
|
||
|
|
func (e *Ent) SetNameTag(s string) {
|
||
|
|
e.data.Name = s
|
||
|
|
for _, v := range e.tx.Viewers(e.Position()) {
|
||
|
|
v.ViewEntityState(e)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Tick ticks Ent, progressing its lifetime and closing the entity if it is
|
||
|
|
// in the void.
|
||
|
|
func (e *Ent) Tick(tx *world.Tx, current int64) {
|
||
|
|
y := e.data.Pos[1]
|
||
|
|
if y < float64(tx.Range()[0]) && current%10 == 0 {
|
||
|
|
_ = e.Close()
|
||
|
|
return
|
||
|
|
}
|
||
|
|
e.SetOnFire(e.OnFireDuration() - time.Second/20)
|
||
|
|
|
||
|
|
if m := e.Behaviour().Tick(e, tx); m != nil {
|
||
|
|
m.Send()
|
||
|
|
}
|
||
|
|
e.data.Age += time.Second / 20
|
||
|
|
}
|
||
|
|
|
||
|
|
// Close closes the Ent and removes the associated entity from the world.
|
||
|
|
func (e *Ent) Close() error {
|
||
|
|
e.once.Do(func() {
|
||
|
|
e.tx.RemoveEntity(e)
|
||
|
|
_ = e.handle.Close()
|
||
|
|
})
|
||
|
|
return nil
|
||
|
|
}
|