summaryrefslogtreecommitdiff
path: root/world.lua
blob: ec35d07d5212e8c0f2a0a788fbea13a6079b78ce (plain)
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
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))
	self.world:unreg_component(c)
	if c.disable then c:disable() 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