Files

142 lines
3.6 KiB
Go
Raw Permalink Normal View History

2026-07-09 08:33:57 +08:00
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
}