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
|
local obj_proto = {}
local obj_mt = {__newindex = function()assert(false)end}
function obj_proto:get(ct)
assert(ct, "component type")
return self.components[ct]
end
function obj_proto:all_components()
local k, v
return function()
k, v = next(self.components, k)
return v
end
end
function obj_proto:call(method, ...)
for c in self:all_components() do
if c[method] then
c[method](c, ...)
end
end
end
function obj_proto:enable()
self.world:registered(self, nil, true)
for c in self:all_components() do
self.world:registered(self, c.component_type, true)
if c.enable then c:enable() end
end
end
function obj_proto:disable()
self.world:registered(self, nil, false)
for c in self:all_components() do
self.world:registered(self, c.component_type, false)
if c.disable then c:disable() end
end
end
function obj_mt:__index(k)
return obj_proto[k] or self:get(k)
end
local function init_cmp(obj, c)
assert(not c.inited)
c.obj = obj
for _, dep in ipairs(c.deps) do
local ct, inst = unpack(dep)
assert(ct, "component type")
obj:require(ct, inst)
end
c:init(c.i)
if c.enable then c:enable() end
c.inited = true
end
function obj_proto:add(c)
assert(not self.components[c.component_type])
self.components[c.component_type] = c
init_cmp(self, c)
return c
end
function obj_proto:remove(ct)
local c = assert(self:get(ct))
for oc in obj:all_components() do
for d in ipairs(oc.deps) do
assert(d[1] ~= ct, "dependency")
end
end
self.world:unreg_component(c)
if c.disable then c:disable() end
if c.remove then c:remove() end
end
function obj_proto:require(ct, instance)
if self:get(ct) then return end
return self:add(ct(instance))
end
local world_proto = {}
local world_mt = {__index = world_proto}
local function world()
local w = setmetatable({objects = {}, components = {}}, world_mt)
return w
end
-- create an object in the world with the components specified in the arguments
function world_proto:object(...)
local components = {...}
local o = setmetatable({world = self, components = {}}, obj_mt)
for _, c in ipairs(components) do
assert(type(c) == 'table')
o.components[c.component_type] = c
end
for _, c in pairs(o.components) do
if not c.inited then
init_cmp(o, c)
end
end
o:enable()
return o
end
function world_proto:registered(object, ct, is_reg)
if ct then
self.components[ct] = self.components[ct] or {}
self.components[ct][object] = is_reg and true or nil
else
self.objects[object] = is_reg and true or nil
end
end
function world_proto:iterate(ct)
if ct then
return pairs(self.components[ct] or {})
else
return pairs(self.objects)
end
end
return world
|