-
Notifications
You must be signed in to change notification settings - Fork 150
/
ent.go
185 lines (158 loc) · 4.2 KB
/
ent.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
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) *Movement
}
// Config allows specifying options that influence the way an Ent behaves.
type Config struct {
Behaviour Behaviour
}
// New creates a new Ent using conf. The entity has a type and a position.
func (conf Config) New(t world.EntityType, pos mgl64.Vec3) *Ent {
return &Ent{t: t, pos: pos, conf: conf}
}
// 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 {
conf Config
t world.EntityType
mu sync.Mutex
pos mgl64.Vec3
vel mgl64.Vec3
rot cube.Rotation
name string
fireDuration time.Duration
age time.Duration
}
// 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.conf.Behaviour.(interface {
Explode(e *Ent, src mgl64.Vec3, impact float64, conf block.ExplosionConfig)
}); ok {
expl.Explode(e, src, impact, conf)
}
}
// Type returns the world.EntityType passed to Config.New.
func (e *Ent) Type() world.EntityType {
return e.t
}
func (e *Ent) Behaviour() Behaviour {
return e.conf.Behaviour
}
// Position returns the current position of the entity.
func (e *Ent) Position() mgl64.Vec3 {
e.mu.Lock()
defer e.mu.Unlock()
return e.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 {
e.mu.Lock()
defer e.mu.Unlock()
return e.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.mu.Lock()
defer e.mu.Unlock()
e.vel = v
}
// Rotation returns the rotation of the entity.
func (e *Ent) Rotation() cube.Rotation {
e.mu.Lock()
defer e.mu.Unlock()
return e.rot
}
// World returns the world of the entity.
func (e *Ent) World() *world.World {
w, _ := world.OfEntity(e)
return w
}
// 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 {
e.mu.Lock()
defer e.mu.Unlock()
return e.age
}
// OnFireDuration ...
func (e *Ent) OnFireDuration() time.Duration {
e.mu.Lock()
defer e.mu.Unlock()
return e.fireDuration
}
// SetOnFire ...
func (e *Ent) SetOnFire(duration time.Duration) {
if duration < 0 {
duration = 0
}
e.mu.Lock()
before, after := e.fireDuration > 0, duration > 0
e.fireDuration = duration
pos := e.pos
e.mu.Unlock()
if before == after {
return
}
for _, v := range e.World().Viewers(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 {
e.mu.Lock()
defer e.mu.Unlock()
return e.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.mu.Lock()
e.name = s
e.mu.Unlock()
for _, v := range e.World().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(w *world.World, current int64) {
e.mu.Lock()
y := e.pos[1]
e.mu.Unlock()
if y < float64(w.Range()[0]) && current%10 == 0 {
_ = e.Close()
return
}
e.SetOnFire(e.OnFireDuration() - time.Second/20)
if m := e.conf.Behaviour.Tick(e); m != nil {
m.Send()
}
e.mu.Lock()
e.age += time.Second / 20
e.mu.Unlock()
}
// Close closes the Ent and removes the associated entity from the world.
func (e *Ent) Close() error {
e.World().RemoveEntity(e)
return nil
}