-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathentity.lua
More file actions
192 lines (166 loc) · 4.44 KB
/
Copy pathentity.lua
File metadata and controls
192 lines (166 loc) · 4.44 KB
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
186
187
188
189
190
191
192
local entity = class()
function entity:new(kernel)
self.kernel = kernel
self.all_behaviours = {}
self.named_behaviours = {}
self.subscriptions = {}
self.destroyed = false
end
function entity.__index(self, name)
local v = rawget(self, name)
if v ~= nil then
return v
end
local b = rawget(self, "named_behaviours")
b = b and b[name]
if b ~= nil then
return b
end
return entity[name]
end
function entity:add(behaviour)
if type(behaviour) == "string" then
error("attempt to add string as behaviour; did you mean add_named")
end
self:error_if_destroyed()
self.kernel:add(behaviour)
table.insert(self.all_behaviours, behaviour)
return behaviour
end
function entity:add_named(name, behaviour)
self.named_behaviours[name] = behaviour
return self:add(behaviour)
end
function entity:add_from_system(system_name, ...)
self:error_if_destroyed()
local behaviour = self.kernel:add_from_system(system_name, ...)
table.insert(self.all_behaviours, behaviour)
return behaviour
end
function entity:add_named_from_system(system_name, name, ...)
local behaviour = self:add_from_system(system_name, ...)
self.named_behaviours[name] = behaviour
return behaviour
end
function entity:name_for(behaviour)
for k, v in pairs(self.named_behaviours) do
if v == behaviour then
return k
end
end
return nil
end
function entity:_behaviour_and_name(behaviour_or_name)
local behaviour, name
if type(behaviour_or_name) == "string" then
name = behaviour_or_name
behaviour = self.named_behaviours[name]
else
behaviour = behaviour_or_name
name = self:name_for(behaviour)
end
return behaviour, name
end
function entity:remove(behaviour_or_name)
local behaviour, name = self:_behaviour_and_name(behaviour_or_name)
if self:detach(behaviour_or_name) then
self.kernel:remove(behaviour)
end
end
--make a behaviour independent of this entity,
--so it is not removed from the kernel when the entity is destroyed
--can be used to transfer to another entity or take over management
function entity:detach(behaviour_or_name)
self:error_if_destroyed()
local behaviour, name = self:_behaviour_and_name(behaviour_or_name)
if table.remove_value(self.all_behaviours, behaviour) then
if not name then
name = self:name_for(behaviour)
end
if name then
self.named_behaviours[name] = nil
end
return true
end
return false
end
--attach a behaviour which has already been added to the kernel
--so that it gets cleaned up with this entity
function entity:attach(name_or_behaviour, behaviour_if_named)
local name, behaviour
if type(name_or_behaviour) == "string" then
name = name_or_behaviour
behaviour = behaviour_if_named
else
name = nil
behaviour = name_or_behaviour
end
table.insert(self.all_behaviours, behaviour)
if name then
self.named_behaviours[name] = behaviour
end
end
--remove everything and mark destroyed
function entity:destroy()
self.kernel:defer(function()
if self.destroyed then return end --double destroyed in one frame
--clean up components
for i, v in ripairs(self.all_behaviours) do
self:remove(v)
end
--unsub everything
for i, v in ripairs(self.subscriptions) do
self.kernel.event:unsubscribe(v[1], v[2])
table.remove(self.subscriptions, i)
end
--do this in a hot minute
self.kernel:defer(function()
self.destroyed = true
self.enabled = false
end)
end)
end
function entity:error_if_destroyed()
if self.destroyed then
error("entity used after destruction")
return
end
end
--event handling proxied through the kernel
function entity:publish(event, ...)
self:error_if_destroyed()
self.kernel.event:publish(event, ...)
end
function entity:subscribe(event, f)
self:error_if_destroyed()
self.kernel.event:subscribe(event, f)
table.insert(self.subscriptions, {event, f})
end
function entity:subscribe_once(event, f)
self:error_if_destroyed()
f = self.kernel.event:subscribe_once(event, f)
table.insert(self.subscriptions, {event, f})
end
function entity:unsubscribe(event, f)
self:error_if_destroyed()
self.kernel.event:unsubscribe(event, f)
for i, v in ipairs(self.subscriptions) do
if v[1] == event and v[2] == f then
table.remove(self.subscriptions, i)
break
end
end
end
--sorting and ordering functions
function entity.behaviour_sort_order(a)
return a.order or 0
end
function entity.less(a, b)
return entity.behaviour_sort_order(a) < entity.behaviour_sort_order(b)
end
function entity.draw_less(a, b)
a = a.draw_order or a.order or 0
b = b.draw_order or b.order or 0
return a < b
end
return entity